Merge "SDK_INT is not "current" on unreleased builds."
diff --git a/Android.mk b/Android.mk
index 9fbdde7..335fb73 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,7 @@
# EventLogTags files.
LOCAL_SRC_FILES += \
core/java/android/content/EventLogTags.logtags \
+ core/java/android/speech/tts/EventLogTags.logtags \
core/java/android/webkit/EventLogTags.logtags \
telephony/java/com/android/internal/telephony/EventLogTags.logtags \
diff --git a/api/current.txt b/api/current.txt
index 1e13e24..2923805 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -312,10 +312,15 @@
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int color = 16843173; // 0x10101a5
+ field public static final int colorActivatedHighlight = 16843684; // 0x10103a4
field public static final int colorBackground = 16842801; // 0x1010031
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
+ field public static final int colorFocusedHighlight = 16843683; // 0x10103a3
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
+ field public static final int colorLongPressedHighlight = 16843682; // 0x10103a2
+ field public static final int colorMultiSelectHighlight = 16843685; // 0x10103a5
+ field public static final int colorPressedHighlight = 16843681; // 0x10103a1
field public static final int columnCount = 16843638; // 0x1010376
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843639; // 0x1010377
@@ -941,6 +946,7 @@
field public static final int tension = 16843370; // 0x101026a
field public static final int testOnly = 16843378; // 0x1010272
field public static final int text = 16843087; // 0x101014f
+ field public static final int textAllCaps = 16843680; // 0x10103a0
field public static final int textAppearance = 16842804; // 0x1010034
field public static final int textAppearanceButton = 16843271; // 0x1010207
field public static final int textAppearanceInverse = 16842805; // 0x1010035
@@ -1120,6 +1126,16 @@
field public static final int background_light = 17170447; // 0x106000f
field public static final int black = 17170444; // 0x106000c
field public static final int darker_gray = 17170432; // 0x1060000
+ field public static final int holo_blue_bright = 17170459; // 0x106001b
+ field public static final int holo_blue_dark = 17170451; // 0x1060013
+ field public static final int holo_blue_light = 17170450; // 0x1060012
+ field public static final int holo_green_dark = 17170453; // 0x1060015
+ field public static final int holo_green_light = 17170452; // 0x1060014
+ field public static final int holo_orange_dark = 17170457; // 0x1060019
+ field public static final int holo_orange_light = 17170456; // 0x1060018
+ field public static final int holo_purple = 17170458; // 0x106001a
+ field public static final int holo_red_dark = 17170455; // 0x1060017
+ field public static final int holo_red_light = 17170454; // 0x1060016
field public static final int primary_text_dark = 17170433; // 0x1060001
field public static final int primary_text_dark_nodisable = 17170434; // 0x1060002
field public static final int primary_text_light = 17170435; // 0x1060003
@@ -14998,6 +15014,257 @@
field public static final deprecated java.lang.String URL = "url";
}
+ public final class CalendarContract {
+ field public static final java.lang.String ACCOUNT_TYPE_LOCAL = "LOCAL";
+ field public static final java.lang.String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
+ field public static final java.lang.String AUTHORITY = "com.android.calendar";
+ field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String EXTRA_EVENT_BEGIN_TIME = "beginTime";
+ field public static final java.lang.String EXTRA_EVENT_END_TIME = "endTime";
+ }
+
+ public static final class CalendarContract.Attendees implements android.provider.BaseColumns android.provider.CalendarContract.AttendeesColumns android.provider.CalendarContract.EventsColumns {
+ method public static final android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ protected static abstract interface CalendarContract.AttendeesColumns {
+ field public static final java.lang.String ATTENDEE_EMAIL = "attendeeEmail";
+ field public static final java.lang.String ATTENDEE_NAME = "attendeeName";
+ field public static final java.lang.String ATTENDEE_RELATIONSHIP = "attendeeRelationship";
+ field public static final java.lang.String ATTENDEE_STATUS = "attendeeStatus";
+ field public static final int ATTENDEE_STATUS_ACCEPTED = 1; // 0x1
+ field public static final int ATTENDEE_STATUS_DECLINED = 2; // 0x2
+ field public static final int ATTENDEE_STATUS_INVITED = 3; // 0x3
+ field public static final int ATTENDEE_STATUS_NONE = 0; // 0x0
+ field public static final int ATTENDEE_STATUS_TENTATIVE = 4; // 0x4
+ field public static final java.lang.String ATTENDEE_TYPE = "attendeeType";
+ field public static final java.lang.String EVENT_ID = "event_id";
+ field public static final int RELATIONSHIP_ATTENDEE = 1; // 0x1
+ field public static final int RELATIONSHIP_NONE = 0; // 0x0
+ field public static final int RELATIONSHIP_ORGANIZER = 2; // 0x2
+ field public static final int RELATIONSHIP_PERFORMER = 3; // 0x3
+ field public static final int RELATIONSHIP_SPEAKER = 4; // 0x4
+ 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
+ }
+
+ public static final class CalendarContract.CalendarAlerts implements android.provider.BaseColumns android.provider.CalendarContract.CalendarAlertsColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final android.net.Uri CONTENT_URI_BY_INSTANCE;
+ }
+
+ protected static abstract interface CalendarContract.CalendarAlertsColumns {
+ field public static final java.lang.String ALARM_TIME = "alarmTime";
+ field public static final java.lang.String BEGIN = "begin";
+ field public static final java.lang.String CREATION_TIME = "creationTime";
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "begin ASC,title ASC";
+ field public static final java.lang.String END = "end";
+ field public static final java.lang.String EVENT_ID = "event_id";
+ field public static final java.lang.String MINUTES = "minutes";
+ field public static final java.lang.String NOTIFY_TIME = "notifyTime";
+ field public static final java.lang.String RECEIVED_TIME = "receivedTime";
+ field public static final java.lang.String STATE = "state";
+ field public static final int STATE_DISMISSED = 2; // 0x2
+ field public static final int STATE_FIRED = 1; // 0x1
+ field public static final int STATE_SCHEDULED = 0; // 0x0
+ }
+
+ public static final class CalendarContract.CalendarCache implements android.provider.CalendarContract.CalendarCacheColumns {
+ field public static final java.lang.String KEY_TIMEZONE_INSTANCES = "timezoneInstances";
+ field public static final java.lang.String KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+ field public static final java.lang.String KEY_TIMEZONE_TYPE = "timezoneType";
+ field public static final java.lang.String TIMEZONE_TYPE_AUTO = "auto";
+ field public static final java.lang.String TIMEZONE_TYPE_HOME = "home";
+ field public static final android.net.Uri URI;
+ }
+
+ protected static abstract interface CalendarContract.CalendarCacheColumns {
+ field public static final java.lang.String KEY = "key";
+ field public static final java.lang.String VALUE = "value";
+ }
+
+ protected static abstract interface CalendarContract.CalendarColumns {
+ 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_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
+ field public static final int CAL_ACCESS_EDITOR = 600; // 0x258
+ field public static final int CAL_ACCESS_FREEBUSY = 100; // 0x64
+ field public static final int CAL_ACCESS_NONE = 0; // 0x0
+ field public static final int CAL_ACCESS_OVERRIDE = 400; // 0x190
+ field public static final int CAL_ACCESS_OWNER = 700; // 0x2bc
+ field public static final int CAL_ACCESS_READ = 200; // 0xc8
+ field public static final int CAL_ACCESS_RESPOND = 300; // 0x12c
+ field public static final int CAL_ACCESS_ROOT = 800; // 0x320
+ field public static final java.lang.String CAN_MODIFY_TIME_ZONE = "canModifyTimeZone";
+ field public static final java.lang.String CAN_ORGANIZER_RESPOND = "canOrganizerRespond";
+ field public static final java.lang.String MAX_REMINDERS = "maxReminders";
+ field public static final java.lang.String OWNER_ACCOUNT = "ownerAccount";
+ field public static final java.lang.String SYNC_EVENTS = "sync_events";
+ field public static final java.lang.String VISIBLE = "visible";
+ }
+
+ public static final class CalendarContract.CalendarEntity implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
+ method public static android.content.EntityIterator newEntityIterator(android.database.Cursor);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ protected static abstract interface CalendarContract.CalendarSyncColumns {
+ field public static final java.lang.String CAL_SYNC1 = "cal_sync1";
+ field public static final java.lang.String CAL_SYNC10 = "cal_sync10";
+ field public static final java.lang.String CAL_SYNC2 = "cal_sync2";
+ field public static final java.lang.String CAL_SYNC3 = "cal_sync3";
+ field public static final java.lang.String CAL_SYNC4 = "cal_sync4";
+ field public static final java.lang.String CAL_SYNC5 = "cal_sync5";
+ field public static final java.lang.String CAL_SYNC6 = "cal_sync6";
+ field public static final java.lang.String CAL_SYNC7 = "cal_sync7";
+ field public static final java.lang.String CAL_SYNC8 = "cal_sync8";
+ field public static final java.lang.String CAL_SYNC9 = "cal_sync9";
+ }
+
+ public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
+ field public static final java.lang.String CALENDAR_LOCATION = "calendar_location";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "displayName";
+ field public static final java.lang.String NAME = "name";
+ }
+
+ 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;
+ }
+
+ protected static abstract interface CalendarContract.EventDaysColumns {
+ field public static final java.lang.String ENDDAY = "endDay";
+ field public static final java.lang.String STARTDAY = "startDay";
+ }
+
+ public static final class CalendarContract.Events implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns {
+ field public static final android.net.Uri CONTENT_EXCEPTION_URI;
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ protected static abstract interface CalendarContract.EventsColumns {
+ field public static final int ACCESS_CONFIDENTIAL = 1; // 0x1
+ field public static final int ACCESS_DEFAULT = 0; // 0x0
+ field public static final java.lang.String ACCESS_LEVEL = "accessLevel";
+ field public static final int ACCESS_PRIVATE = 2; // 0x2
+ field public static final int ACCESS_PUBLIC = 3; // 0x3
+ field public static final java.lang.String ALL_DAY = "allDay";
+ 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 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";
+ field public static final java.lang.String DTEND = "dtend";
+ 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_END_TIMEZONE = "eventEndTimezone";
+ field public static final java.lang.String EVENT_LOCATION = "eventLocation";
+ field public static final java.lang.String EVENT_TIMEZONE = "eventTimezone";
+ field public static final java.lang.String EXDATE = "exdate";
+ field public static final java.lang.String EXRULE = "exrule";
+ field public static final java.lang.String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers";
+ field public static final java.lang.String GUESTS_CAN_MODIFY = "guestsCanModify";
+ field public static final java.lang.String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests";
+ field public static final java.lang.String HAS_ALARM = "hasAlarm";
+ field public static final java.lang.String HAS_ATTENDEE_DATA = "hasAttendeeData";
+ field public static final java.lang.String HAS_EXTENDED_PROPERTIES = "hasExtendedProperties";
+ field public static final java.lang.String LAST_DATE = "lastDate";
+ field public static final java.lang.String LAST_SYNCED = "lastSynced";
+ field public static final java.lang.String ORGANIZER = "organizer";
+ field public static final java.lang.String ORIGINAL_ALL_DAY = "originalAllDay";
+ field public static final java.lang.String ORIGINAL_ID = "original_id";
+ field public static final java.lang.String ORIGINAL_INSTANCE_TIME = "originalInstanceTime";
+ field public static final java.lang.String ORIGINAL_SYNC_ID = "original_sync_id";
+ field public static final java.lang.String RDATE = "rdate";
+ field public static final java.lang.String RRULE = "rrule";
+ field public static final java.lang.String SELF_ATTENDEE_STATUS = "selfAttendeeStatus";
+ field public static final java.lang.String STATUS = "eventStatus";
+ field public static final int STATUS_CANCELED = 2; // 0x2
+ field public static final int STATUS_CONFIRMED = 1; // 0x1
+ field public static final int STATUS_TENTATIVE = 0; // 0x0
+ field public static final java.lang.String SYNC_DATA1 = "sync_data1";
+ field public static final java.lang.String SYNC_DATA10 = "sync_data10";
+ field public static final java.lang.String SYNC_DATA2 = "sync_data2";
+ field public static final java.lang.String SYNC_DATA3 = "sync_data3";
+ field public static final java.lang.String SYNC_DATA4 = "sync_data4";
+ field public static final java.lang.String SYNC_DATA5 = "sync_data5";
+ field public static final java.lang.String SYNC_DATA6 = "sync_data6";
+ field public static final java.lang.String SYNC_DATA7 = "sync_data7";
+ field public static final java.lang.String SYNC_DATA8 = "sync_data8";
+ field public static final java.lang.String SYNC_DATA9 = "sync_data9";
+ field public static final java.lang.String TITLE = "title";
+ }
+
+ public static final class CalendarContract.EventsEntity implements android.provider.BaseColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns {
+ method public static android.content.EntityIterator newEntityIterator(android.database.Cursor, android.content.ContentResolver);
+ method public static android.content.EntityIterator newEntityIterator(android.database.Cursor, android.content.ContentProviderClient);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class CalendarContract.ExtendedProperties implements android.provider.BaseColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.ExtendedPropertiesColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ protected static abstract interface CalendarContract.ExtendedPropertiesColumns {
+ field public static final java.lang.String EVENT_ID = "event_id";
+ field public static final java.lang.String NAME = "name";
+ field public static final java.lang.String VALUE = "value";
+ }
+
+ public static final class CalendarContract.Instances implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns {
+ method public static final android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long);
+ method public static final android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long, java.lang.String);
+ field public static final java.lang.String BEGIN = "begin";
+ field public static final android.net.Uri CONTENT_BY_DAY_URI;
+ field public static final android.net.Uri CONTENT_SEARCH_BY_DAY_URI;
+ field public static final android.net.Uri CONTENT_SEARCH_URI;
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String END = "end";
+ field public static final java.lang.String END_DAY = "endDay";
+ field public static final java.lang.String END_MINUTE = "endMinute";
+ field public static final java.lang.String EVENT_ID = "event_id";
+ field public static final java.lang.String START_DAY = "startDay";
+ field public static final java.lang.String START_MINUTE = "startMinute";
+ }
+
+ public static final class CalendarContract.Reminders implements android.provider.BaseColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.RemindersColumns {
+ method public static final android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ protected static abstract interface CalendarContract.RemindersColumns {
+ field public static final java.lang.String EVENT_ID = "event_id";
+ field public static final java.lang.String METHOD = "method";
+ field public static final int METHOD_ALERT = 1; // 0x1
+ field public static final int METHOD_DEFAULT = 0; // 0x0
+ field public static final int METHOD_EMAIL = 2; // 0x2
+ field public static final int METHOD_SMS = 3; // 0x3
+ field public static final java.lang.String MINUTES = "minutes";
+ field public static final int MINUTES_DEFAULT = -1; // 0xffffffff
+ }
+
+ protected static abstract interface CalendarContract.SyncColumns implements android.provider.CalendarContract.CalendarSyncColumns {
+ 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 CAN_PARTIALLY_UPDATE = "canPartiallyUpdate";
+ field public static final java.lang.String DELETED = "deleted";
+ field public static final java.lang.String DIRTY = "dirty";
+ field public static final java.lang.String _SYNC_ID = "_sync_id";
+ }
+
+ public static final class CalendarContract.SyncState implements android.provider.SyncStateContract.Columns {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
public class CallLog {
ctor public CallLog();
field public static final java.lang.String AUTHORITY = "call_log";
@@ -22473,7 +22740,7 @@
method public void requestDisallowInterceptTouchEvent(boolean);
method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void requestTransparentRegion(android.view.View);
- method protected void resetLayoutDirectionResolution();
+ method protected void resetResolvedLayoutDirection();
method public void scheduleLayoutAnimation();
method public void setAddStatesFromChildren(boolean);
method public void setAlwaysDrawnWithCacheEnabled(boolean);
@@ -26150,7 +26417,8 @@
method protected void onTextChanged(java.lang.CharSequence, int, int, int);
method public boolean onTextContextMenuItem(int);
method public void removeTextChangedListener(android.text.TextWatcher);
- method protected void resetLayoutDirectionResolution();
+ method protected void resetResolvedLayoutDirection();
+ method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 38d0d2a..2666b41 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,6 +23,8 @@
import android.os.RemoteException;
import android.os.ServiceManager;
+import java.util.HashSet;
+
public final class Bmgr {
IBackupManager mBmgr;
IRestoreSession mRestore;
@@ -45,7 +47,6 @@
}
public void run(String[] args) {
- boolean validCommand = false;
if (args.length < 1) {
showUsage();
return;
@@ -329,7 +330,13 @@
} else {
try {
long token = Long.parseLong(arg, 16);
- doRestoreAll(token);
+ HashSet<String> filter = null;
+ while ((arg = nextArg()) != null) {
+ if (filter == null) filter = new HashSet<String>();
+ filter.add(arg);
+ }
+
+ doRestoreAll(token, filter);
} catch (NumberFormatException e) {
showUsage();
return;
@@ -364,7 +371,7 @@
}
}
- private void doRestoreAll(long token) {
+ private void doRestoreAll(long token, HashSet<String> filter) {
RestoreObserver observer = new RestoreObserver();
try {
@@ -383,7 +390,13 @@
for (RestoreSet s : sets) {
if (s.token == token) {
System.out.println("Scheduling restore: " + s.name);
- didRestore = (mRestore.restoreAll(token, observer) == 0);
+ if (filter == null) {
+ didRestore = (mRestore.restoreAll(token, observer) == 0);
+ } else {
+ String[] names = new String[filter.size()];
+ filter.toArray(names);
+ didRestore = (mRestore.restoreSome(token, observer, names) == 0);
+ }
break;
}
}
@@ -430,6 +443,7 @@
System.err.println(" bmgr list sets");
System.err.println(" bmgr transport WHICH");
System.err.println(" bmgr restore TOKEN");
+ System.err.println(" bmgr restore TOKEN PACKAGE...");
System.err.println(" bmgr restore PACKAGE");
System.err.println(" bmgr run");
System.err.println(" bmgr wipe PACKAGE");
@@ -457,12 +471,18 @@
System.err.println("The 'transport' command designates the named transport as the currently");
System.err.println("active one. This setting is persistent across reboots.");
System.err.println("");
- System.err.println("The 'restore' command when given a restore token initiates a full-system");
+ System.err.println("The 'restore' command when given just a restore token initiates a full-system");
System.err.println("restore operation from the currently active transport. It will deliver");
System.err.println("the restore set designated by the TOKEN argument to each application");
System.err.println("that had contributed data to that restore set.");
System.err.println("");
- System.err.println("The 'restore' command when given a package name intiates a restore of");
+ System.err.println("The 'restore' command when given a token and one or more package names");
+ System.err.println("initiates a restore operation of just those given packages from the restore");
+ System.err.println("set designated by the TOKEN argument. It is effectively the same as the");
+ System.err.println("'restore' operation supplying only a token, but applies a filter to the");
+ System.err.println("set of applications to be restored.");
+ System.err.println("");
+ System.err.println("The 'restore' command when given just a package name intiates a restore of");
System.err.println("just that one package according to the restore set selection algorithm");
System.err.println("used by the RestoreSession.restorePackage() method.");
System.err.println("");
diff --git a/core/java/android/app/backup/IRestoreSession.aidl b/core/java/android/app/backup/IRestoreSession.aidl
index 1dddbb0..14731ee 100644
--- a/core/java/android/app/backup/IRestoreSession.aidl
+++ b/core/java/android/app/backup/IRestoreSession.aidl
@@ -52,6 +52,25 @@
int restoreAll(long token, IRestoreObserver observer);
/**
+ * Restore select packages from the given set onto the device, replacing the
+ * current data of any app contained in the set with the data previously
+ * backed up.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @return Zero on success, nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
+ * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+ * the restore set that should be used.
+ * @param observer If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param packages The set of packages for which to attempt a restore. Regardless of
+ * the contents of the actual back-end dataset named by {@code token}, only
+ * applications mentioned in this list will have their data restored.
+ */
+ int restoreSome(long token, IRestoreObserver observer, in String[] packages);
+
+ /**
* Restore a single application from backup. The data will be restored from the
* current backup dataset if the given package has stored data there, or from
* the dataset used during the last full device setup operation if the current
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index 24ddb99..7181c61 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -87,6 +87,40 @@
}
/**
+ * Restore select packages from the given set onto the device, replacing the
+ * current data of any app contained in the set with the data previously
+ * backed up.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @return Zero on success, nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
+ * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+ * the restore set that should be used.
+ * @param observer If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param packages The set of packages for which to attempt a restore. Regardless of
+ * the contents of the actual back-end dataset named by {@code token}, only
+ * applications mentioned in this list will have their data restored.
+ *
+ * @hide
+ */
+ public int restoreSome(long token, RestoreObserver observer, String[] packages) {
+ int err = -1;
+ if (mObserver != null) {
+ Log.d(TAG, "restoreAll() called during active restore");
+ return -1;
+ }
+ mObserver = new RestoreObserverWrapper(mContext, observer);
+ try {
+ err = mBinder.restoreSome(token, mObserver, packages);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Can't contact server to restore packages");
+ }
+ return err;
+ }
+
+ /**
* Restore a single application from backup. The data will be restored from the
* current backup dataset if the given package has stored data there, or from
* the dataset used during the last full device setup operation if the current
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 83e59e2..acce182 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -62,6 +62,7 @@
/*package*/ final BluetoothSocket mSocket;
private Handler mHandler;
private int mMessage;
+ private final int mChannel;
/**
* Construct a socket for incoming connections.
@@ -74,6 +75,7 @@
*/
/*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
throws IOException {
+ mChannel = port;
mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null);
}
@@ -125,4 +127,12 @@
mHandler = handler;
mMessage = message;
}
+
+ /**
+ * Returns the channel on which this socket is bound.
+ * @hide
+ */
+ public int getChannel() {
+ return mChannel;
+ }
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 8a678d6..76534ef 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -38,8 +38,22 @@
/** Bring the named network interface down. */
public native static int disableInterface(String interfaceName);
- /** Reset any sockets that are connected via the named interface. */
- public native static int resetConnections(String interfaceName);
+ /** Setting bit 0 indicates reseting of IPv4 addresses required */
+ public static final int RESET_IPV4_ADDRESSES = 0x01;
+
+ /** Setting bit 1 indicates reseting of IPv4 addresses required */
+ public static final int RESET_IPV6_ADDRESSES = 0x02;
+
+ /** Reset all addresses */
+ public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES;
+
+ /**
+ * Reset IPv6 or IPv4 sockets that are connected via the named interface.
+ *
+ * @param interfaceName is the interface to reset
+ * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES}
+ */
+ public native static int resetConnections(String interfaceName, int mask);
/**
* Start the DHCP client daemon, in order to have it request addresses
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 792e4c1..60900e1 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -34,6 +34,8 @@
private final int mMtpReserveSpace;
private final boolean mAllowMassStorage;
private int mStorageId;
+ // maximum file size for the storage, or zero for no limit
+ private final long mMaxFileSize;
// StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
// ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED,
@@ -41,18 +43,20 @@
public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
public StorageVolume(String path, String description, boolean removable,
- boolean emulated, int mtpReserveSpace, boolean allowMassStorage) {
+ boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize) {
mPath = path;
mDescription = description;
mRemovable = removable;
mEmulated = emulated;
mMtpReserveSpace = mtpReserveSpace;
mAllowMassStorage = allowMassStorage;
+ mMaxFileSize = maxFileSize;
}
// for parcelling only
private StorageVolume(String path, String description, boolean removable,
- boolean emulated, int mtpReserveSpace, int storageId, boolean allowMassStorage) {
+ boolean emulated, int mtpReserveSpace, int storageId,
+ boolean allowMassStorage, long maxFileSize) {
mPath = path;
mDescription = description;
mRemovable = removable;
@@ -60,6 +64,7 @@
mMtpReserveSpace = mtpReserveSpace;
mAllowMassStorage = allowMassStorage;
mStorageId = storageId;
+ mMaxFileSize = maxFileSize;
}
/**
@@ -142,6 +147,15 @@
return mAllowMassStorage;
}
+ /**
+ * Returns maximum file size for the volume, or zero if it is unbounded.
+ *
+ * @return maximum file size
+ */
+ public long getMaxFileSize() {
+ return mMaxFileSize;
+ }
+
@Override
public boolean equals(Object obj) {
if (obj instanceof StorageVolume && mPath != null) {
@@ -171,9 +185,10 @@
int storageId = in.readInt();
int mtpReserveSpace = in.readInt();
int allowMassStorage = in.readInt();
+ long maxFileSize = in.readLong();
return new StorageVolume(path, description,
- removable == 1, emulated == 1,
- mtpReserveSpace, storageId, allowMassStorage == 1);
+ removable == 1, emulated == 1, mtpReserveSpace,
+ storageId, allowMassStorage == 1, maxFileSize);
}
public StorageVolume[] newArray(int size) {
@@ -193,5 +208,6 @@
parcel.writeInt(mStorageId);
parcel.writeInt(mMtpReserveSpace);
parcel.writeInt(mAllowMassStorage ? 1 : 0);
+ parcel.writeLong(mMaxFileSize);
}
}
diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java
deleted file mode 100644
index 128b697..0000000
--- a/core/java/android/pim/EventRecurrence.java
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.text.TextUtils;
-import android.text.format.Time;
-import android.util.Log;
-import android.util.TimeFormatException;
-
-import java.util.Calendar;
-import java.util.HashMap;
-
-/**
- * Event recurrence utility functions.
- */
-public class EventRecurrence {
- private static String TAG = "EventRecur";
-
- public static final int SECONDLY = 1;
- public static final int MINUTELY = 2;
- public static final int HOURLY = 3;
- public static final int DAILY = 4;
- public static final int WEEKLY = 5;
- public static final int MONTHLY = 6;
- public static final int YEARLY = 7;
-
- public static final int SU = 0x00010000;
- public static final int MO = 0x00020000;
- public static final int TU = 0x00040000;
- public static final int WE = 0x00080000;
- public static final int TH = 0x00100000;
- public static final int FR = 0x00200000;
- public static final int SA = 0x00400000;
-
- public Time startDate; // set by setStartDate(), not parse()
-
- public int freq; // SECONDLY, MINUTELY, etc.
- public String until;
- public int count;
- public int interval;
- public int wkst; // SU, MO, TU, etc.
-
- /* lists with zero entries may be null references */
- public int[] bysecond;
- public int bysecondCount;
- public int[] byminute;
- public int byminuteCount;
- public int[] byhour;
- public int byhourCount;
- public int[] byday;
- public int[] bydayNum;
- public int bydayCount;
- public int[] bymonthday;
- public int bymonthdayCount;
- public int[] byyearday;
- public int byyeardayCount;
- public int[] byweekno;
- public int byweeknoCount;
- public int[] bymonth;
- public int bymonthCount;
- public int[] bysetpos;
- public int bysetposCount;
-
- /** maps a part string to a parser object */
- private static HashMap<String,PartParser> sParsePartMap;
- static {
- sParsePartMap = new HashMap<String,PartParser>();
- sParsePartMap.put("FREQ", new ParseFreq());
- sParsePartMap.put("UNTIL", new ParseUntil());
- sParsePartMap.put("COUNT", new ParseCount());
- sParsePartMap.put("INTERVAL", new ParseInterval());
- sParsePartMap.put("BYSECOND", new ParseBySecond());
- sParsePartMap.put("BYMINUTE", new ParseByMinute());
- sParsePartMap.put("BYHOUR", new ParseByHour());
- sParsePartMap.put("BYDAY", new ParseByDay());
- sParsePartMap.put("BYMONTHDAY", new ParseByMonthDay());
- sParsePartMap.put("BYYEARDAY", new ParseByYearDay());
- sParsePartMap.put("BYWEEKNO", new ParseByWeekNo());
- sParsePartMap.put("BYMONTH", new ParseByMonth());
- sParsePartMap.put("BYSETPOS", new ParseBySetPos());
- sParsePartMap.put("WKST", new ParseWkst());
- }
-
- /* values for bit vector that keeps track of what we have already seen */
- private static final int PARSED_FREQ = 1 << 0;
- private static final int PARSED_UNTIL = 1 << 1;
- private static final int PARSED_COUNT = 1 << 2;
- private static final int PARSED_INTERVAL = 1 << 3;
- private static final int PARSED_BYSECOND = 1 << 4;
- private static final int PARSED_BYMINUTE = 1 << 5;
- private static final int PARSED_BYHOUR = 1 << 6;
- private static final int PARSED_BYDAY = 1 << 7;
- private static final int PARSED_BYMONTHDAY = 1 << 8;
- private static final int PARSED_BYYEARDAY = 1 << 9;
- private static final int PARSED_BYWEEKNO = 1 << 10;
- private static final int PARSED_BYMONTH = 1 << 11;
- private static final int PARSED_BYSETPOS = 1 << 12;
- private static final int PARSED_WKST = 1 << 13;
-
- /** maps a FREQ value to an integer constant */
- private static final HashMap<String,Integer> sParseFreqMap = new HashMap<String,Integer>();
- static {
- sParseFreqMap.put("SECONDLY", SECONDLY);
- sParseFreqMap.put("MINUTELY", MINUTELY);
- sParseFreqMap.put("HOURLY", HOURLY);
- sParseFreqMap.put("DAILY", DAILY);
- sParseFreqMap.put("WEEKLY", WEEKLY);
- sParseFreqMap.put("MONTHLY", MONTHLY);
- sParseFreqMap.put("YEARLY", YEARLY);
- }
-
- /** maps a two-character weekday string to an integer constant */
- private static final HashMap<String,Integer> sParseWeekdayMap = new HashMap<String,Integer>();
- static {
- sParseWeekdayMap.put("SU", SU);
- sParseWeekdayMap.put("MO", MO);
- sParseWeekdayMap.put("TU", TU);
- sParseWeekdayMap.put("WE", WE);
- sParseWeekdayMap.put("TH", TH);
- sParseWeekdayMap.put("FR", FR);
- sParseWeekdayMap.put("SA", SA);
- }
-
- /** If set, allow lower-case recurrence rule strings. Minor performance impact. */
- private static final boolean ALLOW_LOWER_CASE = false;
-
- /** If set, validate the value of UNTIL parts. Minor performance impact. */
- private static final boolean VALIDATE_UNTIL = false;
-
- /** If set, require that only one of {UNTIL,COUNT} is present. Breaks compat w/ old parser. */
- private static final boolean ONLY_ONE_UNTIL_COUNT = false;
-
-
- /**
- * Thrown when a recurrence string provided can not be parsed according
- * to RFC2445.
- */
- public static class InvalidFormatException extends RuntimeException {
- InvalidFormatException(String s) {
- super(s);
- }
- }
-
-
- public void setStartDate(Time date) {
- startDate = date;
- }
-
- /**
- * Converts one of the Calendar.SUNDAY constants to the SU, MO, etc.
- * constants. btw, I think we should switch to those here too, to
- * get rid of this function, if possible.
- */
- public static int calendarDay2Day(int day)
- {
- switch (day)
- {
- case Calendar.SUNDAY:
- return SU;
- case Calendar.MONDAY:
- return MO;
- case Calendar.TUESDAY:
- return TU;
- case Calendar.WEDNESDAY:
- return WE;
- case Calendar.THURSDAY:
- return TH;
- case Calendar.FRIDAY:
- return FR;
- case Calendar.SATURDAY:
- return SA;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
-
- public static int timeDay2Day(int day)
- {
- switch (day)
- {
- case Time.SUNDAY:
- return SU;
- case Time.MONDAY:
- return MO;
- case Time.TUESDAY:
- return TU;
- case Time.WEDNESDAY:
- return WE;
- case Time.THURSDAY:
- return TH;
- case Time.FRIDAY:
- return FR;
- case Time.SATURDAY:
- return SA;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
- public static int day2TimeDay(int day)
- {
- switch (day)
- {
- case SU:
- return Time.SUNDAY;
- case MO:
- return Time.MONDAY;
- case TU:
- return Time.TUESDAY;
- case WE:
- return Time.WEDNESDAY;
- case TH:
- return Time.THURSDAY;
- case FR:
- return Time.FRIDAY;
- case SA:
- return Time.SATURDAY;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
-
- /**
- * Converts one of the SU, MO, etc. constants to the Calendar.SUNDAY
- * constants. btw, I think we should switch to those here too, to
- * get rid of this function, if possible.
- */
- public static int day2CalendarDay(int day)
- {
- switch (day)
- {
- case SU:
- return Calendar.SUNDAY;
- case MO:
- return Calendar.MONDAY;
- case TU:
- return Calendar.TUESDAY;
- case WE:
- return Calendar.WEDNESDAY;
- case TH:
- return Calendar.THURSDAY;
- case FR:
- return Calendar.FRIDAY;
- case SA:
- return Calendar.SATURDAY;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
-
- /**
- * Converts one of the internal day constants (SU, MO, etc.) to the
- * two-letter string representing that constant.
- *
- * @param day one the internal constants SU, MO, etc.
- * @return the two-letter string for the day ("SU", "MO", etc.)
- *
- * @throws IllegalArgumentException Thrown if the day argument is not one of
- * the defined day constants.
- */
- private static String day2String(int day) {
- switch (day) {
- case SU:
- return "SU";
- case MO:
- return "MO";
- case TU:
- return "TU";
- case WE:
- return "WE";
- case TH:
- return "TH";
- case FR:
- return "FR";
- case SA:
- return "SA";
- default:
- throw new IllegalArgumentException("bad day argument: " + day);
- }
- }
-
- private static void appendNumbers(StringBuilder s, String label,
- int count, int[] values)
- {
- if (count > 0) {
- s.append(label);
- count--;
- for (int i=0; i<count; i++) {
- s.append(values[i]);
- s.append(",");
- }
- s.append(values[count]);
- }
- }
-
- private void appendByDay(StringBuilder s, int i)
- {
- int n = this.bydayNum[i];
- if (n != 0) {
- s.append(n);
- }
-
- String str = day2String(this.byday[i]);
- s.append(str);
- }
-
- @Override
- public String toString()
- {
- StringBuilder s = new StringBuilder();
-
- s.append("FREQ=");
- switch (this.freq)
- {
- case SECONDLY:
- s.append("SECONDLY");
- break;
- case MINUTELY:
- s.append("MINUTELY");
- break;
- case HOURLY:
- s.append("HOURLY");
- break;
- case DAILY:
- s.append("DAILY");
- break;
- case WEEKLY:
- s.append("WEEKLY");
- break;
- case MONTHLY:
- s.append("MONTHLY");
- break;
- case YEARLY:
- s.append("YEARLY");
- break;
- }
-
- if (!TextUtils.isEmpty(this.until)) {
- s.append(";UNTIL=");
- s.append(until);
- }
-
- if (this.count != 0) {
- s.append(";COUNT=");
- s.append(this.count);
- }
-
- if (this.interval != 0) {
- s.append(";INTERVAL=");
- s.append(this.interval);
- }
-
- if (this.wkst != 0) {
- s.append(";WKST=");
- s.append(day2String(this.wkst));
- }
-
- appendNumbers(s, ";BYSECOND=", this.bysecondCount, this.bysecond);
- appendNumbers(s, ";BYMINUTE=", this.byminuteCount, this.byminute);
- appendNumbers(s, ";BYSECOND=", this.byhourCount, this.byhour);
-
- // day
- int count = this.bydayCount;
- if (count > 0) {
- s.append(";BYDAY=");
- count--;
- for (int i=0; i<count; i++) {
- appendByDay(s, i);
- s.append(",");
- }
- appendByDay(s, count);
- }
-
- appendNumbers(s, ";BYMONTHDAY=", this.bymonthdayCount, this.bymonthday);
- appendNumbers(s, ";BYYEARDAY=", this.byyeardayCount, this.byyearday);
- appendNumbers(s, ";BYWEEKNO=", this.byweeknoCount, this.byweekno);
- appendNumbers(s, ";BYMONTH=", this.bymonthCount, this.bymonth);
- appendNumbers(s, ";BYSETPOS=", this.bysetposCount, this.bysetpos);
-
- return s.toString();
- }
-
- public boolean repeatsOnEveryWeekDay() {
- if (this.freq != WEEKLY) {
- return false;
- }
-
- int count = this.bydayCount;
- if (count != 5) {
- return false;
- }
-
- for (int i = 0 ; i < count ; i++) {
- int day = byday[i];
- if (day == SU || day == SA) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Determines whether this rule specifies a simple monthly rule by weekday, such as
- * "FREQ=MONTHLY;BYDAY=3TU" (the 3rd Tuesday of every month).
- * <p>
- * Negative days, e.g. "FREQ=MONTHLY;BYDAY=-1TU" (the last Tuesday of every month),
- * will cause "false" to be returned.
- * <p>
- * Rules that fire every week, such as "FREQ=MONTHLY;BYDAY=TU" (every Tuesday of every
- * month) will cause "false" to be returned. (Note these are usually expressed as
- * WEEKLY rules, and hence are uncommon.)
- *
- * @return true if this rule is of the appropriate form
- */
- public boolean repeatsMonthlyOnDayCount() {
- if (this.freq != MONTHLY) {
- return false;
- }
-
- if (bydayCount != 1 || bymonthdayCount != 0) {
- return false;
- }
-
- if (bydayNum[0] <= 0) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Determines whether two integer arrays contain identical elements.
- * <p>
- * The native implementation over-allocated the arrays (and may have stuff left over from
- * a previous run), so we can't just check the arrays -- the separately-maintained count
- * field also matters. We assume that a null array will have a count of zero, and that the
- * array can hold as many elements as the associated count indicates.
- * <p>
- * TODO: replace this with Arrays.equals() when the old parser goes away.
- */
- private static boolean arraysEqual(int[] array1, int count1, int[] array2, int count2) {
- if (count1 != count2) {
- return false;
- }
-
- for (int i = 0; i < count1; i++) {
- if (array1[i] != array2[i])
- return false;
- }
-
- return true;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof EventRecurrence)) {
- return false;
- }
-
- EventRecurrence er = (EventRecurrence) obj;
- return (startDate == null ?
- er.startDate == null : Time.compare(startDate, er.startDate) == 0) &&
- freq == er.freq &&
- (until == null ? er.until == null : until.equals(er.until)) &&
- count == er.count &&
- interval == er.interval &&
- wkst == er.wkst &&
- arraysEqual(bysecond, bysecondCount, er.bysecond, er.bysecondCount) &&
- arraysEqual(byminute, byminuteCount, er.byminute, er.byminuteCount) &&
- arraysEqual(byhour, byhourCount, er.byhour, er.byhourCount) &&
- arraysEqual(byday, bydayCount, er.byday, er.bydayCount) &&
- arraysEqual(bydayNum, bydayCount, er.bydayNum, er.bydayCount) &&
- arraysEqual(bymonthday, bymonthdayCount, er.bymonthday, er.bymonthdayCount) &&
- arraysEqual(byyearday, byyeardayCount, er.byyearday, er.byyeardayCount) &&
- arraysEqual(byweekno, byweeknoCount, er.byweekno, er.byweeknoCount) &&
- arraysEqual(bymonth, bymonthCount, er.bymonth, er.bymonthCount) &&
- arraysEqual(bysetpos, bysetposCount, er.bysetpos, er.bysetposCount);
- }
-
- @Override public int hashCode() {
- // We overrode equals, so we must override hashCode(). Nobody seems to need this though.
- throw new UnsupportedOperationException();
- }
-
- /**
- * Resets parser-modified fields to their initial state. Does not alter startDate.
- * <p>
- * The original parser always set all of the "count" fields, "wkst", and "until",
- * essentially allowing the same object to be used multiple times by calling parse().
- * It's unclear whether this behavior was intentional. For now, be paranoid and
- * preserve the existing behavior by resetting the fields.
- * <p>
- * We don't need to touch the integer arrays; they will either be ignored or
- * overwritten. The "startDate" field is not set by the parser, so we ignore it here.
- */
- private void resetFields() {
- until = null;
- freq = count = interval = bysecondCount = byminuteCount = byhourCount =
- bydayCount = bymonthdayCount = byyeardayCount = byweeknoCount = bymonthCount =
- bysetposCount = 0;
- }
-
- /**
- * Parses an rfc2445 recurrence rule string into its component pieces. Attempting to parse
- * malformed input will result in an EventRecurrence.InvalidFormatException.
- *
- * @param recur The recurrence rule to parse (in un-folded form).
- */
- public void parse(String recur) {
- /*
- * From RFC 2445 section 4.3.10:
- *
- * recur = "FREQ"=freq *(
- * ; either UNTIL or COUNT may appear in a 'recur',
- * ; but UNTIL and COUNT MUST NOT occur in the same 'recur'
- *
- * ( ";" "UNTIL" "=" enddate ) /
- * ( ";" "COUNT" "=" 1*DIGIT ) /
- *
- * ; the rest of these keywords are optional,
- * ; but MUST NOT occur more than once
- *
- * ( ";" "INTERVAL" "=" 1*DIGIT ) /
- * ( ";" "BYSECOND" "=" byseclist ) /
- * ( ";" "BYMINUTE" "=" byminlist ) /
- * ( ";" "BYHOUR" "=" byhrlist ) /
- * ( ";" "BYDAY" "=" bywdaylist ) /
- * ( ";" "BYMONTHDAY" "=" bymodaylist ) /
- * ( ";" "BYYEARDAY" "=" byyrdaylist ) /
- * ( ";" "BYWEEKNO" "=" bywknolist ) /
- * ( ";" "BYMONTH" "=" bymolist ) /
- * ( ";" "BYSETPOS" "=" bysplist ) /
- * ( ";" "WKST" "=" weekday ) /
- * ( ";" x-name "=" text )
- * )
- *
- * Examples:
- * FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
- * FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
- *
- * Strategy:
- * (1) Split the string at ';' boundaries to get an array of rule "parts".
- * (2) For each part, find substrings for left/right sides of '=' (name/value).
- * (3) Call a <name>-specific parsing function to parse the <value> into an
- * output field.
- *
- * By keeping track of which names we've seen in a bit vector, we can verify the
- * constraints indicated above (FREQ appears first, none of them appear more than once --
- * though x-[name] would require special treatment), and we have either UNTIL or COUNT
- * but not both.
- *
- * In general, RFC 2445 property names (e.g. "FREQ") and enumerations ("TU") must
- * be handled in a case-insensitive fashion, but case may be significant for other
- * properties. We don't have any case-sensitive values in RRULE, except possibly
- * for the custom "X-" properties, but we ignore those anyway. Thus, we can trivially
- * convert the entire string to upper case and then use simple comparisons.
- *
- * Differences from previous version:
- * - allows lower-case property and enumeration values [optional]
- * - enforces that FREQ appears first
- * - enforces that only one of UNTIL and COUNT may be specified
- * - allows (but ignores) X-* parts
- * - improved validation on various values (e.g. UNTIL timestamps)
- * - error messages are more specific
- */
-
- /* TODO: replace with "if (freq != 0) throw" if nothing requires this */
- resetFields();
-
- int parseFlags = 0;
- String[] parts;
- if (ALLOW_LOWER_CASE) {
- parts = recur.toUpperCase().split(";");
- } else {
- parts = recur.split(";");
- }
- for (String part : parts) {
- int equalIndex = part.indexOf('=');
- if (equalIndex <= 0) {
- /* no '=' or no LHS */
- throw new InvalidFormatException("Missing LHS in " + part);
- }
-
- String lhs = part.substring(0, equalIndex);
- String rhs = part.substring(equalIndex + 1);
- if (rhs.length() == 0) {
- throw new InvalidFormatException("Missing RHS in " + part);
- }
-
- /*
- * In lieu of a "switch" statement that allows string arguments, we use a
- * map from strings to parsing functions.
- */
- PartParser parser = sParsePartMap.get(lhs);
- if (parser == null) {
- if (lhs.startsWith("X-")) {
- //Log.d(TAG, "Ignoring custom part " + lhs);
- continue;
- }
- throw new InvalidFormatException("Couldn't find parser for " + lhs);
- } else {
- int flag = parser.parsePart(rhs, this);
- if ((parseFlags & flag) != 0) {
- throw new InvalidFormatException("Part " + lhs + " was specified twice");
- }
- if (parseFlags == 0 && flag != PARSED_FREQ) {
- throw new InvalidFormatException("FREQ must be specified first");
- }
- parseFlags |= flag;
- }
- }
-
- // If not specified, week starts on Monday.
- if ((parseFlags & PARSED_WKST) == 0) {
- wkst = MO;
- }
-
- // FREQ is mandatory.
- if ((parseFlags & PARSED_FREQ) == 0) {
- throw new InvalidFormatException("Must specify a FREQ value");
- }
-
- // Can't have both UNTIL and COUNT.
- if ((parseFlags & (PARSED_UNTIL | PARSED_COUNT)) == (PARSED_UNTIL | PARSED_COUNT)) {
- if (ONLY_ONE_UNTIL_COUNT) {
- throw new InvalidFormatException("Must not specify both UNTIL and COUNT: " + recur);
- } else {
- Log.w(TAG, "Warning: rrule has both UNTIL and COUNT: " + recur);
- }
- }
- }
-
- /**
- * Base class for the RRULE part parsers.
- */
- abstract static class PartParser {
- /**
- * Parses a single part.
- *
- * @param value The right-hand-side of the part.
- * @param er The EventRecurrence into which the result is stored.
- * @return A bit value indicating which part was parsed.
- */
- public abstract int parsePart(String value, EventRecurrence er);
-
- /**
- * Parses an integer, with range-checking.
- *
- * @param str The string to parse.
- * @param minVal Minimum allowed value.
- * @param maxVal Maximum allowed value.
- * @param allowZero Is 0 allowed?
- * @return The parsed value.
- */
- public static int parseIntRange(String str, int minVal, int maxVal, boolean allowZero) {
- try {
- if (str.charAt(0) == '+') {
- // Integer.parseInt does not allow a leading '+', so skip it manually.
- str = str.substring(1);
- }
- int val = Integer.parseInt(str);
- if (val < minVal || val > maxVal || (val == 0 && !allowZero)) {
- throw new InvalidFormatException("Integer value out of range: " + str);
- }
- return val;
- } catch (NumberFormatException nfe) {
- throw new InvalidFormatException("Invalid integer value: " + str);
- }
- }
-
- /**
- * Parses a comma-separated list of integers, with range-checking.
- *
- * @param listStr The string to parse.
- * @param minVal Minimum allowed value.
- * @param maxVal Maximum allowed value.
- * @param allowZero Is 0 allowed?
- * @return A new array with values, sized to hold the exact number of elements.
- */
- public static int[] parseNumberList(String listStr, int minVal, int maxVal,
- boolean allowZero) {
- int[] values;
-
- if (listStr.indexOf(",") < 0) {
- // Common case: only one entry, skip split() overhead.
- values = new int[1];
- values[0] = parseIntRange(listStr, minVal, maxVal, allowZero);
- } else {
- String[] valueStrs = listStr.split(",");
- int len = valueStrs.length;
- values = new int[len];
- for (int i = 0; i < len; i++) {
- values[i] = parseIntRange(valueStrs[i], minVal, maxVal, allowZero);
- }
- }
- return values;
- }
- }
-
- /** parses FREQ={SECONDLY,MINUTELY,...} */
- private static class ParseFreq extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- Integer freq = sParseFreqMap.get(value);
- if (freq == null) {
- throw new InvalidFormatException("Invalid FREQ value: " + value);
- }
- er.freq = freq;
- return PARSED_FREQ;
- }
- }
- /** parses UNTIL=enddate, e.g. "19970829T021400" */
- private static class ParseUntil extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- if (VALIDATE_UNTIL) {
- try {
- // Parse the time to validate it. The result isn't retained.
- Time until = new Time();
- until.parse(value);
- } catch (TimeFormatException tfe) {
- throw new InvalidFormatException("Invalid UNTIL value: " + value);
- }
- }
- er.until = value;
- return PARSED_UNTIL;
- }
- }
- /** parses COUNT=[non-negative-integer] */
- private static class ParseCount extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- er.count = parseIntRange(value, 0, Integer.MAX_VALUE, true);
- return PARSED_COUNT;
- }
- }
- /** parses INTERVAL=[non-negative-integer] */
- private static class ParseInterval extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- er.interval = parseIntRange(value, 1, Integer.MAX_VALUE, false);
- return PARSED_INTERVAL;
- }
- }
- /** parses BYSECOND=byseclist */
- private static class ParseBySecond extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bysecond = parseNumberList(value, 0, 59, true);
- er.bysecond = bysecond;
- er.bysecondCount = bysecond.length;
- return PARSED_BYSECOND;
- }
- }
- /** parses BYMINUTE=byminlist */
- private static class ParseByMinute extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byminute = parseNumberList(value, 0, 59, true);
- er.byminute = byminute;
- er.byminuteCount = byminute.length;
- return PARSED_BYMINUTE;
- }
- }
- /** parses BYHOUR=byhrlist */
- private static class ParseByHour extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byhour = parseNumberList(value, 0, 23, true);
- er.byhour = byhour;
- er.byhourCount = byhour.length;
- return PARSED_BYHOUR;
- }
- }
- /** parses BYDAY=bywdaylist, e.g. "1SU,-1SU" */
- private static class ParseByDay extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byday;
- int[] bydayNum;
- int bydayCount;
-
- if (value.indexOf(",") < 0) {
- /* only one entry, skip split() overhead */
- bydayCount = 1;
- byday = new int[1];
- bydayNum = new int[1];
- parseWday(value, byday, bydayNum, 0);
- } else {
- String[] wdays = value.split(",");
- int len = wdays.length;
- bydayCount = len;
- byday = new int[len];
- bydayNum = new int[len];
- for (int i = 0; i < len; i++) {
- parseWday(wdays[i], byday, bydayNum, i);
- }
- }
- er.byday = byday;
- er.bydayNum = bydayNum;
- er.bydayCount = bydayCount;
- return PARSED_BYDAY;
- }
-
- /** parses [int]weekday, putting the pieces into parallel array entries */
- private static void parseWday(String str, int[] byday, int[] bydayNum, int index) {
- int wdayStrStart = str.length() - 2;
- String wdayStr;
-
- if (wdayStrStart > 0) {
- /* number is included; parse it out and advance to weekday */
- String numPart = str.substring(0, wdayStrStart);
- int num = parseIntRange(numPart, -53, 53, false);
- bydayNum[index] = num;
- wdayStr = str.substring(wdayStrStart);
- } else {
- /* just the weekday string */
- wdayStr = str;
- }
- Integer wday = sParseWeekdayMap.get(wdayStr);
- if (wday == null) {
- throw new InvalidFormatException("Invalid BYDAY value: " + str);
- }
- byday[index] = wday;
- }
- }
- /** parses BYMONTHDAY=bymodaylist */
- private static class ParseByMonthDay extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bymonthday = parseNumberList(value, -31, 31, false);
- er.bymonthday = bymonthday;
- er.bymonthdayCount = bymonthday.length;
- return PARSED_BYMONTHDAY;
- }
- }
- /** parses BYYEARDAY=byyrdaylist */
- private static class ParseByYearDay extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byyearday = parseNumberList(value, -366, 366, false);
- er.byyearday = byyearday;
- er.byyeardayCount = byyearday.length;
- return PARSED_BYYEARDAY;
- }
- }
- /** parses BYWEEKNO=bywknolist */
- private static class ParseByWeekNo extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byweekno = parseNumberList(value, -53, 53, false);
- er.byweekno = byweekno;
- er.byweeknoCount = byweekno.length;
- return PARSED_BYWEEKNO;
- }
- }
- /** parses BYMONTH=bymolist */
- private static class ParseByMonth extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bymonth = parseNumberList(value, 1, 12, false);
- er.bymonth = bymonth;
- er.bymonthCount = bymonth.length;
- return PARSED_BYMONTH;
- }
- }
- /** parses BYSETPOS=bysplist */
- private static class ParseBySetPos extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bysetpos = parseNumberList(value, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
- er.bysetpos = bysetpos;
- er.bysetposCount = bysetpos.length;
- return PARSED_BYSETPOS;
- }
- }
- /** parses WKST={SU,MO,...} */
- private static class ParseWkst extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- Integer wkst = sParseWeekdayMap.get(value);
- if (wkst == null) {
- throw new InvalidFormatException("Invalid WKST value: " + value);
- }
- er.wkst = wkst;
- return PARSED_WKST;
- }
- }
-}
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
deleted file mode 100644
index 58c5c63..0000000
--- a/core/java/android/pim/ICalendar.java
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.util.Log;
-
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.ArrayList;
-
-/**
- * Parses RFC 2445 iCalendar objects.
- */
-public class ICalendar {
-
- private static final String TAG = "Sync";
-
- // TODO: keep track of VEVENT, VTODO, VJOURNAL, VFREEBUSY, VTIMEZONE, VALARM
- // components, by type field or by subclass? subclass would allow us to
- // enforce grammars.
-
- /**
- * Exception thrown when an iCalendar object has invalid syntax.
- */
- public static class FormatException extends Exception {
- public FormatException() {
- super();
- }
-
- public FormatException(String msg) {
- super(msg);
- }
-
- public FormatException(String msg, Throwable cause) {
- super(msg, cause);
- }
- }
-
- /**
- * A component within an iCalendar (VEVENT, VTODO, VJOURNAL, VFEEBUSY,
- * VTIMEZONE, VALARM).
- */
- public static class Component {
-
- // components
- private static final String BEGIN = "BEGIN";
- private static final String END = "END";
- private static final String NEWLINE = "\n";
- public static final String VCALENDAR = "VCALENDAR";
- public static final String VEVENT = "VEVENT";
- public static final String VTODO = "VTODO";
- public static final String VJOURNAL = "VJOURNAL";
- public static final String VFREEBUSY = "VFREEBUSY";
- public static final String VTIMEZONE = "VTIMEZONE";
- public static final String VALARM = "VALARM";
-
- private final String mName;
- private final Component mParent; // see if we can get rid of this
- private LinkedList<Component> mChildren = null;
- private final LinkedHashMap<String, ArrayList<Property>> mPropsMap =
- new LinkedHashMap<String, ArrayList<Property>>();
-
- /**
- * Creates a new component with the provided name.
- * @param name The name of the component.
- */
- public Component(String name, Component parent) {
- mName = name;
- mParent = parent;
- }
-
- /**
- * Returns the name of the component.
- * @return The name of the component.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the parent of this component.
- * @return The parent of this component.
- */
- public Component getParent() {
- return mParent;
- }
-
- /**
- * Helper that lazily gets/creates the list of children.
- * @return The list of children.
- */
- protected LinkedList<Component> getOrCreateChildren() {
- if (mChildren == null) {
- mChildren = new LinkedList<Component>();
- }
- return mChildren;
- }
-
- /**
- * Adds a child component to this component.
- * @param child The child component.
- */
- public void addChild(Component child) {
- getOrCreateChildren().add(child);
- }
-
- /**
- * Returns a list of the Component children of this component. May be
- * null, if there are no children.
- *
- * @return A list of the children.
- */
- public List<Component> getComponents() {
- return mChildren;
- }
-
- /**
- * Adds a Property to this component.
- * @param prop
- */
- public void addProperty(Property prop) {
- String name= prop.getName();
- ArrayList<Property> props = mPropsMap.get(name);
- if (props == null) {
- props = new ArrayList<Property>();
- mPropsMap.put(name, props);
- }
- props.add(prop);
- }
-
- /**
- * Returns a set of the property names within this component.
- * @return A set of property names within this component.
- */
- public Set<String> getPropertyNames() {
- return mPropsMap.keySet();
- }
-
- /**
- * Returns a list of properties with the specified name. Returns null
- * if there are no such properties.
- * @param name The name of the property that should be returned.
- * @return A list of properties with the requested name.
- */
- public List<Property> getProperties(String name) {
- return mPropsMap.get(name);
- }
-
- /**
- * Returns the first property with the specified name. Returns null
- * if there is no such property.
- * @param name The name of the property that should be returned.
- * @return The first property with the specified name.
- */
- public Property getFirstProperty(String name) {
- List<Property> props = mPropsMap.get(name);
- if (props == null || props.size() == 0) {
- return null;
- }
- return props.get(0);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- sb.append(NEWLINE);
- return sb.toString();
- }
-
- /**
- * Helper method that appends this component to a StringBuilder. The
- * caller is responsible for appending a newline at the end of the
- * component.
- */
- public void toString(StringBuilder sb) {
- sb.append(BEGIN);
- sb.append(":");
- sb.append(mName);
- sb.append(NEWLINE);
-
- // append the properties
- for (String propertyName : getPropertyNames()) {
- for (Property property : getProperties(propertyName)) {
- property.toString(sb);
- sb.append(NEWLINE);
- }
- }
-
- // append the sub-components
- if (mChildren != null) {
- for (Component component : mChildren) {
- component.toString(sb);
- sb.append(NEWLINE);
- }
- }
-
- sb.append(END);
- sb.append(":");
- sb.append(mName);
- }
- }
-
- /**
- * A property within an iCalendar component (e.g., DTSTART, DTEND, etc.,
- * within a VEVENT).
- */
- public static class Property {
- // properties
- // TODO: do we want to list these here? the complete list is long.
- public static final String DTSTART = "DTSTART";
- public static final String DTEND = "DTEND";
- public static final String DURATION = "DURATION";
- public static final String RRULE = "RRULE";
- public static final String RDATE = "RDATE";
- public static final String EXRULE = "EXRULE";
- public static final String EXDATE = "EXDATE";
- // ... need to add more.
-
- private final String mName;
- private LinkedHashMap<String, ArrayList<Parameter>> mParamsMap =
- new LinkedHashMap<String, ArrayList<Parameter>>();
- private String mValue; // TODO: make this final?
-
- /**
- * Creates a new property with the provided name.
- * @param name The name of the property.
- */
- public Property(String name) {
- mName = name;
- }
-
- /**
- * Creates a new property with the provided name and value.
- * @param name The name of the property.
- * @param value The value of the property.
- */
- public Property(String name, String value) {
- mName = name;
- mValue = value;
- }
-
- /**
- * Returns the name of the property.
- * @return The name of the property.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the value of this property.
- * @return The value of this property.
- */
- public String getValue() {
- return mValue;
- }
-
- /**
- * Sets the value of this property.
- * @param value The desired value for this property.
- */
- public void setValue(String value) {
- mValue = value;
- }
-
- /**
- * Adds a {@link Parameter} to this property.
- * @param param The parameter that should be added.
- */
- public void addParameter(Parameter param) {
- ArrayList<Parameter> params = mParamsMap.get(param.name);
- if (params == null) {
- params = new ArrayList<Parameter>();
- mParamsMap.put(param.name, params);
- }
- params.add(param);
- }
-
- /**
- * Returns the set of parameter names for this property.
- * @return The set of parameter names for this property.
- */
- public Set<String> getParameterNames() {
- return mParamsMap.keySet();
- }
-
- /**
- * Returns the list of parameters with the specified name. May return
- * null if there are no such parameters.
- * @param name The name of the parameters that should be returned.
- * @return The list of parameters with the specified name.
- */
- public List<Parameter> getParameters(String name) {
- return mParamsMap.get(name);
- }
-
- /**
- * Returns the first parameter with the specified name. May return
- * nll if there is no such parameter.
- * @param name The name of the parameter that should be returned.
- * @return The first parameter with the specified name.
- */
- public Parameter getFirstParameter(String name) {
- ArrayList<Parameter> params = mParamsMap.get(name);
- if (params == null || params.size() == 0) {
- return null;
- }
- return params.get(0);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- return sb.toString();
- }
-
- /**
- * Helper method that appends this property to a StringBuilder. The
- * caller is responsible for appending a newline after this property.
- */
- public void toString(StringBuilder sb) {
- sb.append(mName);
- Set<String> parameterNames = getParameterNames();
- for (String parameterName : parameterNames) {
- for (Parameter param : getParameters(parameterName)) {
- sb.append(";");
- param.toString(sb);
- }
- }
- sb.append(":");
- sb.append(mValue);
- }
- }
-
- /**
- * A parameter defined for an iCalendar property.
- */
- // TODO: make this a proper class rather than a struct?
- public static class Parameter {
- public String name;
- public String value;
-
- /**
- * Creates a new empty parameter.
- */
- public Parameter() {
- }
-
- /**
- * Creates a new parameter with the specified name and value.
- * @param name The name of the parameter.
- * @param value The value of the parameter.
- */
- public Parameter(String name, String value) {
- this.name = name;
- this.value = value;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- return sb.toString();
- }
-
- /**
- * Helper method that appends this parameter to a StringBuilder.
- */
- public void toString(StringBuilder sb) {
- sb.append(name);
- sb.append("=");
- sb.append(value);
- }
- }
-
- private static final class ParserState {
- // public int lineNumber = 0;
- public String line; // TODO: just point to original text
- public int index;
- }
-
- // use factory method
- private ICalendar() {
- }
-
- // TODO: get rid of this -- handle all of the parsing in one pass through
- // the text.
- private static String normalizeText(String text) {
- // it's supposed to be \r\n, but not everyone does that
- text = text.replaceAll("\r\n", "\n");
- text = text.replaceAll("\r", "\n");
-
- // we deal with line folding, by replacing all "\n " strings
- // with nothing. The RFC specifies "\r\n " to be folded, but
- // we handle "\n " and "\r " too because we can get those.
- text = text.replaceAll("\n ", "");
-
- return text;
- }
-
- /**
- * Parses text into an iCalendar component. Parses into the provided
- * component, if not null, or parses into a new component. In the latter
- * case, expects a BEGIN as the first line. Returns the provided or newly
- * created top-level component.
- */
- // TODO: use an index into the text, so we can make this a recursive
- // function?
- private static Component parseComponentImpl(Component component,
- String text)
- throws FormatException {
- Component current = component;
- ParserState state = new ParserState();
- state.index = 0;
-
- // split into lines
- String[] lines = text.split("\n");
-
- // each line is of the format:
- // name *(";" param) ":" value
- for (String line : lines) {
- try {
- current = parseLine(line, state, current);
- // if the provided component was null, we will return the root
- // NOTE: in this case, if the first line is not a BEGIN, a
- // FormatException will get thrown.
- if (component == null) {
- component = current;
- }
- } catch (FormatException fe) {
- if (false) {
- Log.v(TAG, "Cannot parse " + line, fe);
- }
- // for now, we ignore the parse error. Google Calendar seems
- // to be emitting some misformatted iCalendar objects.
- }
- continue;
- }
- return component;
- }
-
- /**
- * Parses a line into the provided component. Creates a new component if
- * the line is a BEGIN, adding the newly created component to the provided
- * parent. Returns whatever component is the current one (to which new
- * properties will be added) in the parse.
- */
- private static Component parseLine(String line, ParserState state,
- Component component)
- throws FormatException {
- state.line = line;
- int len = state.line.length();
-
- // grab the name
- char c = 0;
- for (state.index = 0; state.index < len; ++state.index) {
- c = line.charAt(state.index);
- if (c == ';' || c == ':') {
- break;
- }
- }
- String name = line.substring(0, state.index);
-
- if (component == null) {
- if (!Component.BEGIN.equals(name)) {
- throw new FormatException("Expected BEGIN");
- }
- }
-
- Property property;
- if (Component.BEGIN.equals(name)) {
- // start a new component
- String componentName = extractValue(state);
- Component child = new Component(componentName, component);
- if (component != null) {
- component.addChild(child);
- }
- return child;
- } else if (Component.END.equals(name)) {
- // finish the current component
- String componentName = extractValue(state);
- if (component == null ||
- !componentName.equals(component.getName())) {
- throw new FormatException("Unexpected END " + componentName);
- }
- return component.getParent();
- } else {
- property = new Property(name);
- }
-
- if (c == ';') {
- Parameter parameter = null;
- while ((parameter = extractParameter(state)) != null) {
- property.addParameter(parameter);
- }
- }
- String value = extractValue(state);
- property.setValue(value);
- component.addProperty(property);
- return component;
- }
-
- /**
- * Extracts the value ":..." on the current line. The first character must
- * be a ':'.
- */
- private static String extractValue(ParserState state)
- throws FormatException {
- String line = state.line;
- if (state.index >= line.length() || line.charAt(state.index) != ':') {
- throw new FormatException("Expected ':' before end of line in "
- + line);
- }
- String value = line.substring(state.index + 1);
- state.index = line.length() - 1;
- return value;
- }
-
- /**
- * Extracts the next parameter from the line, if any. If there are no more
- * parameters, returns null.
- */
- private static Parameter extractParameter(ParserState state)
- throws FormatException {
- String text = state.line;
- int len = text.length();
- Parameter parameter = null;
- int startIndex = -1;
- int equalIndex = -1;
- while (state.index < len) {
- char c = text.charAt(state.index);
- if (c == ':') {
- if (parameter != null) {
- if (equalIndex == -1) {
- throw new FormatException("Expected '=' within "
- + "parameter in " + text);
- }
- parameter.value = text.substring(equalIndex + 1,
- state.index);
- }
- return parameter; // may be null
- } else if (c == ';') {
- if (parameter != null) {
- if (equalIndex == -1) {
- throw new FormatException("Expected '=' within "
- + "parameter in " + text);
- }
- parameter.value = text.substring(equalIndex + 1,
- state.index);
- return parameter;
- } else {
- parameter = new Parameter();
- startIndex = state.index;
- }
- } else if (c == '=') {
- equalIndex = state.index;
- if ((parameter == null) || (startIndex == -1)) {
- throw new FormatException("Expected ';' before '=' in "
- + text);
- }
- parameter.name = text.substring(startIndex + 1, equalIndex);
- } else if (c == '"') {
- if (parameter == null) {
- throw new FormatException("Expected parameter before '\"' in " + text);
- }
- if (equalIndex == -1) {
- throw new FormatException("Expected '=' within parameter in " + text);
- }
- if (state.index > equalIndex + 1) {
- throw new FormatException("Parameter value cannot contain a '\"' in " + text);
- }
- final int endQuote = text.indexOf('"', state.index + 1);
- if (endQuote < 0) {
- throw new FormatException("Expected closing '\"' in " + text);
- }
- parameter.value = text.substring(state.index + 1, endQuote);
- state.index = endQuote + 1;
- return parameter;
- }
- ++state.index;
- }
- throw new FormatException("Expected ':' before end of line in " + text);
- }
-
- /**
- * Parses the provided text into an iCalendar object. The top-level
- * component must be of type VCALENDAR.
- * @param text The text to be parsed.
- * @return The top-level VCALENDAR component.
- * @throws FormatException Thrown if the text could not be parsed into an
- * iCalendar VCALENDAR object.
- */
- public static Component parseCalendar(String text) throws FormatException {
- Component calendar = parseComponent(null, text);
- if (calendar == null || !Component.VCALENDAR.equals(calendar.getName())) {
- throw new FormatException("Expected " + Component.VCALENDAR);
- }
- return calendar;
- }
-
- /**
- * Parses the provided text into an iCalendar event. The top-level
- * component must be of type VEVENT.
- * @param text The text to be parsed.
- * @return The top-level VEVENT component.
- * @throws FormatException Thrown if the text could not be parsed into an
- * iCalendar VEVENT.
- */
- public static Component parseEvent(String text) throws FormatException {
- Component event = parseComponent(null, text);
- if (event == null || !Component.VEVENT.equals(event.getName())) {
- throw new FormatException("Expected " + Component.VEVENT);
- }
- return event;
- }
-
- /**
- * Parses the provided text into an iCalendar component.
- * @param text The text to be parsed.
- * @return The top-level component.
- * @throws FormatException Thrown if the text could not be parsed into an
- * iCalendar component.
- */
- public static Component parseComponent(String text) throws FormatException {
- return parseComponent(null, text);
- }
-
- /**
- * Parses the provided text, adding to the provided component.
- * @param component The component to which the parsed iCalendar data should
- * be added.
- * @param text The text to be parsed.
- * @return The top-level component.
- * @throws FormatException Thrown if the text could not be parsed as an
- * iCalendar object.
- */
- public static Component parseComponent(Component component, String text)
- throws FormatException {
- text = normalizeText(text);
- return parseComponentImpl(component, text);
- }
-}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
deleted file mode 100644
index b7fb320..0000000
--- a/core/java/android/pim/RecurrenceSet.java
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.provider.CalendarContract;
-import android.text.TextUtils;
-import android.text.format.Time;
-import android.util.Log;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Basic information about a recurrence, following RFC 2445 Section 4.8.5.
- * Contains the RRULEs, RDATE, EXRULEs, and EXDATE properties.
- */
-public class RecurrenceSet {
-
- private final static String TAG = "CalendarProvider";
-
- private final static String RULE_SEPARATOR = "\n";
- private final static String FOLDING_SEPARATOR = "\n ";
-
- // TODO: make these final?
- public EventRecurrence[] rrules = null;
- public long[] rdates = null;
- public EventRecurrence[] exrules = null;
- public long[] exdates = null;
-
- /**
- * Creates a new RecurrenceSet from information stored in the
- * events table in the CalendarProvider.
- * @param values The values retrieved from the Events table.
- */
- public RecurrenceSet(ContentValues values)
- throws EventRecurrence.InvalidFormatException {
- String rruleStr = values.getAsString(CalendarContract.Events.RRULE);
- String rdateStr = values.getAsString(CalendarContract.Events.RDATE);
- String exruleStr = values.getAsString(CalendarContract.Events.EXRULE);
- String exdateStr = values.getAsString(CalendarContract.Events.EXDATE);
- init(rruleStr, rdateStr, exruleStr, exdateStr);
- }
-
- /**
- * Creates a new RecurrenceSet from information stored in a database
- * {@link Cursor} pointing to the events table in the
- * CalendarProvider. The cursor must contain the RRULE, RDATE, EXRULE,
- * and EXDATE columns.
- *
- * @param cursor The cursor containing the RRULE, RDATE, EXRULE, and EXDATE
- * columns.
- */
- public RecurrenceSet(Cursor cursor)
- throws EventRecurrence.InvalidFormatException {
- int rruleColumn = cursor.getColumnIndex(CalendarContract.Events.RRULE);
- int rdateColumn = cursor.getColumnIndex(CalendarContract.Events.RDATE);
- int exruleColumn = cursor.getColumnIndex(CalendarContract.Events.EXRULE);
- int exdateColumn = cursor.getColumnIndex(CalendarContract.Events.EXDATE);
- String rruleStr = cursor.getString(rruleColumn);
- String rdateStr = cursor.getString(rdateColumn);
- String exruleStr = cursor.getString(exruleColumn);
- String exdateStr = cursor.getString(exdateColumn);
- init(rruleStr, rdateStr, exruleStr, exdateStr);
- }
-
- public RecurrenceSet(String rruleStr, String rdateStr,
- String exruleStr, String exdateStr)
- throws EventRecurrence.InvalidFormatException {
- init(rruleStr, rdateStr, exruleStr, exdateStr);
- }
-
- private void init(String rruleStr, String rdateStr,
- String exruleStr, String exdateStr)
- throws EventRecurrence.InvalidFormatException {
- if (!TextUtils.isEmpty(rruleStr) || !TextUtils.isEmpty(rdateStr)) {
-
- if (!TextUtils.isEmpty(rruleStr)) {
- String[] rruleStrs = rruleStr.split(RULE_SEPARATOR);
- rrules = new EventRecurrence[rruleStrs.length];
- for (int i = 0; i < rruleStrs.length; ++i) {
- EventRecurrence rrule = new EventRecurrence();
- rrule.parse(rruleStrs[i]);
- rrules[i] = rrule;
- }
- }
-
- if (!TextUtils.isEmpty(rdateStr)) {
- rdates = parseRecurrenceDates(rdateStr);
- }
-
- if (!TextUtils.isEmpty(exruleStr)) {
- String[] exruleStrs = exruleStr.split(RULE_SEPARATOR);
- exrules = new EventRecurrence[exruleStrs.length];
- for (int i = 0; i < exruleStrs.length; ++i) {
- EventRecurrence exrule = new EventRecurrence();
- exrule.parse(exruleStr);
- exrules[i] = exrule;
- }
- }
-
- if (!TextUtils.isEmpty(exdateStr)) {
- exdates = parseRecurrenceDates(exdateStr);
- }
- }
- }
-
- /**
- * Returns whether or not a recurrence is defined in this RecurrenceSet.
- * @return Whether or not a recurrence is defined in this RecurrenceSet.
- */
- public boolean hasRecurrence() {
- return (rrules != null || rdates != null);
- }
-
- /**
- * Parses the provided RDATE or EXDATE string into an array of longs
- * representing each date/time in the recurrence.
- * @param recurrence The recurrence to be parsed.
- * @return The list of date/times.
- */
- public static long[] parseRecurrenceDates(String recurrence) {
- // TODO: use "local" time as the default. will need to handle times
- // that end in "z" (UTC time) explicitly at that point.
- String tz = Time.TIMEZONE_UTC;
- int tzidx = recurrence.indexOf(";");
- if (tzidx != -1) {
- tz = recurrence.substring(0, tzidx);
- recurrence = recurrence.substring(tzidx + 1);
- }
- Time time = new Time(tz);
- String[] rawDates = recurrence.split(",");
- int n = rawDates.length;
- long[] dates = new long[n];
- for (int i = 0; i<n; ++i) {
- // The timezone is updated to UTC if the time string specified 'Z'.
- time.parse(rawDates[i]);
- dates[i] = time.toMillis(false /* use isDst */);
- time.timezone = tz;
- }
- return dates;
- }
-
- /**
- * Populates the database map of values with the appropriate RRULE, RDATE,
- * EXRULE, and EXDATE values extracted from the parsed iCalendar component.
- * @param component The iCalendar component containing the desired
- * recurrence specification.
- * @param values The db values that should be updated.
- * @return true if the component contained the necessary information
- * to specify a recurrence. The required fields are DTSTART,
- * one of DTEND/DURATION, and one of RRULE/RDATE. Returns false if
- * there was an error, including if the date is out of range.
- */
- public static boolean populateContentValues(ICalendar.Component component,
- ContentValues values) {
- ICalendar.Property dtstartProperty =
- component.getFirstProperty("DTSTART");
- String dtstart = dtstartProperty.getValue();
- ICalendar.Parameter tzidParam =
- dtstartProperty.getFirstParameter("TZID");
- // NOTE: the timezone may be null, if this is a floating time.
- String tzid = tzidParam == null ? null : tzidParam.value;
- Time start = new Time(tzidParam == null ? Time.TIMEZONE_UTC : tzid);
- boolean inUtc = start.parse(dtstart);
- boolean allDay = start.allDay;
-
- // We force TimeZone to UTC for "all day recurring events" as the server is sending no
- // TimeZone in DTSTART for them
- if (inUtc || allDay) {
- tzid = Time.TIMEZONE_UTC;
- }
-
- String duration = computeDuration(start, component);
- String rrule = flattenProperties(component, "RRULE");
- String rdate = extractDates(component.getFirstProperty("RDATE"));
- String exrule = flattenProperties(component, "EXRULE");
- String exdate = extractDates(component.getFirstProperty("EXDATE"));
-
- if ((TextUtils.isEmpty(dtstart))||
- (TextUtils.isEmpty(duration))||
- ((TextUtils.isEmpty(rrule))&&
- (TextUtils.isEmpty(rdate)))) {
- if (false) {
- Log.d(TAG, "Recurrence missing DTSTART, DTEND/DURATION, "
- + "or RRULE/RDATE: "
- + component.toString());
- }
- return false;
- }
-
- if (allDay) {
- start.timezone = Time.TIMEZONE_UTC;
- }
- long millis = start.toMillis(false /* use isDst */);
- values.put(CalendarContract.Events.DTSTART, millis);
- if (millis == -1) {
- if (false) {
- Log.d(TAG, "DTSTART is out of range: " + component.toString());
- }
- return false;
- }
-
- values.put(CalendarContract.Events.RRULE, rrule);
- values.put(CalendarContract.Events.RDATE, rdate);
- values.put(CalendarContract.Events.EXRULE, exrule);
- values.put(CalendarContract.Events.EXDATE, exdate);
- values.put(CalendarContract.Events.EVENT_TIMEZONE, tzid);
- values.put(CalendarContract.Events.DURATION, duration);
- values.put(CalendarContract.Events.ALL_DAY, allDay ? 1 : 0);
- return true;
- }
-
- // This can be removed when the old CalendarSyncAdapter is removed.
- public static boolean populateComponent(Cursor cursor,
- ICalendar.Component component) {
-
- int dtstartColumn = cursor.getColumnIndex(CalendarContract.Events.DTSTART);
- int durationColumn = cursor.getColumnIndex(CalendarContract.Events.DURATION);
- int tzidColumn = cursor.getColumnIndex(CalendarContract.Events.EVENT_TIMEZONE);
- int rruleColumn = cursor.getColumnIndex(CalendarContract.Events.RRULE);
- int rdateColumn = cursor.getColumnIndex(CalendarContract.Events.RDATE);
- int exruleColumn = cursor.getColumnIndex(CalendarContract.Events.EXRULE);
- int exdateColumn = cursor.getColumnIndex(CalendarContract.Events.EXDATE);
- int allDayColumn = cursor.getColumnIndex(CalendarContract.Events.ALL_DAY);
-
-
- long dtstart = -1;
- if (!cursor.isNull(dtstartColumn)) {
- dtstart = cursor.getLong(dtstartColumn);
- }
- String duration = cursor.getString(durationColumn);
- String tzid = cursor.getString(tzidColumn);
- String rruleStr = cursor.getString(rruleColumn);
- String rdateStr = cursor.getString(rdateColumn);
- String exruleStr = cursor.getString(exruleColumn);
- String exdateStr = cursor.getString(exdateColumn);
- boolean allDay = cursor.getInt(allDayColumn) == 1;
-
- if ((dtstart == -1) ||
- (TextUtils.isEmpty(duration))||
- ((TextUtils.isEmpty(rruleStr))&&
- (TextUtils.isEmpty(rdateStr)))) {
- // no recurrence.
- return false;
- }
-
- ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
- Time dtstartTime = null;
- if (!TextUtils.isEmpty(tzid)) {
- if (!allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
- }
- dtstartTime = new Time(tzid);
- } else {
- // use the "floating" timezone
- dtstartTime = new Time(Time.TIMEZONE_UTC);
- }
-
- dtstartTime.set(dtstart);
- // make sure the time is printed just as a date, if all day.
- // TODO: android.pim.Time really should take care of this for us.
- if (allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
- dtstartTime.allDay = true;
- dtstartTime.hour = 0;
- dtstartTime.minute = 0;
- dtstartTime.second = 0;
- }
-
- dtstartProp.setValue(dtstartTime.format2445());
- component.addProperty(dtstartProp);
- ICalendar.Property durationProp = new ICalendar.Property("DURATION");
- durationProp.setValue(duration);
- component.addProperty(durationProp);
-
- addPropertiesForRuleStr(component, "RRULE", rruleStr);
- addPropertyForDateStr(component, "RDATE", rdateStr);
- addPropertiesForRuleStr(component, "EXRULE", exruleStr);
- addPropertyForDateStr(component, "EXDATE", exdateStr);
- return true;
- }
-
-public static boolean populateComponent(ContentValues values,
- ICalendar.Component component) {
- long dtstart = -1;
- if (values.containsKey(CalendarContract.Events.DTSTART)) {
- dtstart = values.getAsLong(CalendarContract.Events.DTSTART);
- }
- String duration = values.getAsString(CalendarContract.Events.DURATION);
- String tzid = values.getAsString(CalendarContract.Events.EVENT_TIMEZONE);
- String rruleStr = values.getAsString(CalendarContract.Events.RRULE);
- String rdateStr = values.getAsString(CalendarContract.Events.RDATE);
- String exruleStr = values.getAsString(CalendarContract.Events.EXRULE);
- String exdateStr = values.getAsString(CalendarContract.Events.EXDATE);
- Integer allDayInteger = values.getAsInteger(CalendarContract.Events.ALL_DAY);
- boolean allDay = (null != allDayInteger) ? (allDayInteger == 1) : false;
-
- if ((dtstart == -1) ||
- (TextUtils.isEmpty(duration))||
- ((TextUtils.isEmpty(rruleStr))&&
- (TextUtils.isEmpty(rdateStr)))) {
- // no recurrence.
- return false;
- }
-
- ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
- Time dtstartTime = null;
- if (!TextUtils.isEmpty(tzid)) {
- if (!allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
- }
- dtstartTime = new Time(tzid);
- } else {
- // use the "floating" timezone
- dtstartTime = new Time(Time.TIMEZONE_UTC);
- }
-
- dtstartTime.set(dtstart);
- // make sure the time is printed just as a date, if all day.
- // TODO: android.pim.Time really should take care of this for us.
- if (allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
- dtstartTime.allDay = true;
- dtstartTime.hour = 0;
- dtstartTime.minute = 0;
- dtstartTime.second = 0;
- }
-
- dtstartProp.setValue(dtstartTime.format2445());
- component.addProperty(dtstartProp);
- ICalendar.Property durationProp = new ICalendar.Property("DURATION");
- durationProp.setValue(duration);
- component.addProperty(durationProp);
-
- addPropertiesForRuleStr(component, "RRULE", rruleStr);
- addPropertyForDateStr(component, "RDATE", rdateStr);
- addPropertiesForRuleStr(component, "EXRULE", exruleStr);
- addPropertyForDateStr(component, "EXDATE", exdateStr);
- return true;
- }
-
- private static void addPropertiesForRuleStr(ICalendar.Component component,
- String propertyName,
- String ruleStr) {
- if (TextUtils.isEmpty(ruleStr)) {
- return;
- }
- String[] rrules = getRuleStrings(ruleStr);
- for (String rrule : rrules) {
- ICalendar.Property prop = new ICalendar.Property(propertyName);
- prop.setValue(rrule);
- component.addProperty(prop);
- }
- }
-
- private static String[] getRuleStrings(String ruleStr) {
- if (null == ruleStr) {
- return new String[0];
- }
- String unfoldedRuleStr = unfold(ruleStr);
- String[] split = unfoldedRuleStr.split(RULE_SEPARATOR);
- int count = split.length;
- for (int n = 0; n < count; n++) {
- split[n] = fold(split[n]);
- }
- return split;
- }
-
-
- private static final Pattern IGNORABLE_ICAL_WHITESPACE_RE =
- Pattern.compile("(?:\\r\\n?|\\n)[ \t]");
-
- private static final Pattern FOLD_RE = Pattern.compile(".{75}");
-
- /**
- * fold and unfolds ical content lines as per RFC 2445 section 4.1.
- *
- * <h3>4.1 Content Lines</h3>
- *
- * <p>The iCalendar object is organized into individual lines of text, called
- * content lines. Content lines are delimited by a line break, which is a CRLF
- * sequence (US-ASCII decimal 13, followed by US-ASCII decimal 10).
- *
- * <p>Lines of text SHOULD NOT be longer than 75 octets, excluding the line
- * break. Long content lines SHOULD be split into a multiple line
- * representations using a line "folding" technique. That is, a long line can
- * be split between any two characters by inserting a CRLF immediately
- * followed by a single linear white space character (i.e., SPACE, US-ASCII
- * decimal 32 or HTAB, US-ASCII decimal 9). Any sequence of CRLF followed
- * immediately by a single linear white space character is ignored (i.e.,
- * removed) when processing the content type.
- */
- public static String fold(String unfoldedIcalContent) {
- return FOLD_RE.matcher(unfoldedIcalContent).replaceAll("$0\r\n ");
- }
-
- public static String unfold(String foldedIcalContent) {
- return IGNORABLE_ICAL_WHITESPACE_RE.matcher(
- foldedIcalContent).replaceAll("");
- }
-
- private static void addPropertyForDateStr(ICalendar.Component component,
- String propertyName,
- String dateStr) {
- if (TextUtils.isEmpty(dateStr)) {
- return;
- }
-
- ICalendar.Property prop = new ICalendar.Property(propertyName);
- String tz = null;
- int tzidx = dateStr.indexOf(";");
- if (tzidx != -1) {
- tz = dateStr.substring(0, tzidx);
- dateStr = dateStr.substring(tzidx + 1);
- }
- if (!TextUtils.isEmpty(tz)) {
- prop.addParameter(new ICalendar.Parameter("TZID", tz));
- }
- prop.setValue(dateStr);
- component.addProperty(prop);
- }
-
- private static String computeDuration(Time start,
- ICalendar.Component component) {
- // see if a duration is defined
- ICalendar.Property durationProperty =
- component.getFirstProperty("DURATION");
- if (durationProperty != null) {
- // just return the duration
- return durationProperty.getValue();
- }
-
- // must compute a duration from the DTEND
- ICalendar.Property dtendProperty =
- component.getFirstProperty("DTEND");
- if (dtendProperty == null) {
- // no DURATION, no DTEND: 0 second duration
- return "+P0S";
- }
- ICalendar.Parameter endTzidParameter =
- dtendProperty.getFirstParameter("TZID");
- String endTzid = (endTzidParameter == null)
- ? start.timezone : endTzidParameter.value;
-
- Time end = new Time(endTzid);
- end.parse(dtendProperty.getValue());
- long durationMillis = end.toMillis(false /* use isDst */)
- - start.toMillis(false /* use isDst */);
- long durationSeconds = (durationMillis / 1000);
- if (start.allDay && (durationSeconds % 86400) == 0) {
- return "P" + (durationSeconds / 86400) + "D"; // Server wants this instead of P86400S
- } else {
- return "P" + durationSeconds + "S";
- }
- }
-
- private static String flattenProperties(ICalendar.Component component,
- String name) {
- List<ICalendar.Property> properties = component.getProperties(name);
- if (properties == null || properties.isEmpty()) {
- return null;
- }
-
- if (properties.size() == 1) {
- return properties.get(0).getValue();
- }
-
- StringBuilder sb = new StringBuilder();
-
- boolean first = true;
- for (ICalendar.Property property : component.getProperties(name)) {
- if (first) {
- first = false;
- } else {
- // TODO: use commas. our RECUR parsing should handle that
- // anyway.
- sb.append(RULE_SEPARATOR);
- }
- sb.append(property.getValue());
- }
- return sb.toString();
- }
-
- private static String extractDates(ICalendar.Property recurrence) {
- if (recurrence == null) {
- return null;
- }
- ICalendar.Parameter tzidParam =
- recurrence.getFirstParameter("TZID");
- if (tzidParam != null) {
- return tzidParam.value + ";" + recurrence.getValue();
- }
- return recurrence.getValue();
- }
-}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index b492615..5b29103 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -17,6 +17,8 @@
package android.provider;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ContentProviderClient;
@@ -83,7 +85,6 @@
* adapters</li>
* </ul>
*
- * @hide
*/
public final class CalendarContract {
private static final String TAG = "Calendar";
@@ -92,8 +93,8 @@
* Broadcast Action: This is the intent that gets fired when an alarm
* notification needs to be posted for a reminder.
*
- * @SdkConstant
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
/**
@@ -146,6 +147,11 @@
public static final String ACCOUNT_TYPE_LOCAL = "LOCAL";
/**
+ * This utility class cannot be instantiated
+ */
+ private CalendarContract() {}
+
+ /**
* Generic columns for use by sync adapters. The specific functions of these
* columns are private to the sync adapter. Other clients of the API should
* not attempt to either read or write this column. These columns are
@@ -384,7 +390,7 @@
* Class that represents a Calendar Entity. There is one entry per calendar.
* This is a helper class to make batch operations easier.
*/
- public static class CalendarEntity implements BaseColumns, SyncColumns, CalendarColumns {
+ public static final class CalendarEntity implements BaseColumns, SyncColumns, CalendarColumns {
/**
* The default Uri used when creating a new calendar EntityIterator.
@@ -394,6 +400,11 @@
"/calendar_entities");
/**
+ * This utility class cannot be instantiated
+ */
+ private CalendarEntity() {}
+
+ /**
* Creates an entity iterator for the given cursor. It assumes the
* cursor contains a calendars query.
*
@@ -566,7 +577,13 @@
* <li>{@link #CAL_SYNC10}</li>
* </ul>
*/
- public static class Calendars implements BaseColumns, SyncColumns, CalendarColumns {
+ public static final class Calendars implements BaseColumns, SyncColumns, CalendarColumns {
+
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Calendars() {}
+
/**
* The content:// style URL for accessing Calendars
*/
@@ -687,7 +704,7 @@
/**
* Fields and helpers for interacting with Attendees. Each row of this table
* represents a single attendee or guest of an event. Calling
- * {@link #query(ContentResolver, long)} will return a list of attendees for
+ * {@link #query(ContentResolver, long, String[])} will return a list of attendees for
* the event with the given eventId. Both apps and sync adapters may write
* to this table. There are six writable fields and all of them except
* {@link #ATTENDEE_NAME} must be included when inserting a new attendee.
@@ -708,24 +725,25 @@
*/
@SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/attendees");
- /**
- * the projection used by the attendees query
- */
- public static final String[] PROJECTION = new String[] {
- _ID, ATTENDEE_NAME, ATTENDEE_EMAIL, ATTENDEE_RELATIONSHIP, ATTENDEE_STATUS,};
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
/**
+ * This utility class cannot be instantiated
+ */
+ private Attendees() {}
+
+ /**
* Queries all attendees associated with the given event. This is a
* blocking call and should not be done on the UI thread.
*
* @param cr The content resolver to use for the query
* @param eventId The id of the event to retrieve attendees for
+ * @param projection the columns to return in the cursor
* @return A Cursor containing all attendees for the event
*/
- public static final Cursor query(ContentResolver cr, long eventId) {
+ public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
String[] attArgs = {Long.toString(eventId)};
- return cr.query(CONTENT_URI, PROJECTION, ATTENDEES_WHERE, attArgs /* selection args */,
+ return cr.query(CONTENT_URI, projection, ATTENDEES_WHERE, attArgs /* selection args */,
null /* sort order */);
}
}
@@ -1068,6 +1086,11 @@
"/event_entities");
/**
+ * This utility class cannot be instantiated
+ */
+ private EventsEntity() {}
+
+ /**
* Creates a new iterator for events
*
* @param cursor An event query
@@ -1411,6 +1434,11 @@
Uri.parse("content://" + AUTHORITY + "/exception");
/**
+ * This utility class cannot be instantiated
+ */
+ private Events() {}
+
+ /**
* The default sort order for this table
*/
private static final String DEFAULT_SORT_ORDER = "";
@@ -1484,6 +1512,11 @@
};
/**
+ * This utility class cannot be instantiated
+ */
+ private Instances() {}
+
+ /**
* Performs a query to return all visible instances in the given range.
* This is a blocking function and should not be done on the UI thread.
* This will cause an expansion of recurring events to fill this time
@@ -1636,7 +1669,7 @@
* time zone for the instances. These settings are stored using a key/value
* scheme. A {@link #KEY} must be specified when updating these values.
*/
- public static class CalendarCache implements CalendarCacheColumns {
+ public static final class CalendarCache implements CalendarCacheColumns {
/**
* The URI to use for retrieving the properties from the Calendar db.
*/
@@ -1644,6 +1677,11 @@
Uri.parse("content://" + AUTHORITY + "/properties");
/**
+ * This utility class cannot be instantiated
+ */
+ private CalendarCache() {}
+
+ /**
* They key for updating the use of auto/home time zones in Calendar.
* Valid values are {@link #TIMEZONE_TYPE_AUTO} or
* {@link #TIMEZONE_TYPE_HOME}.
@@ -1724,6 +1762,11 @@
* @hide
*/
public static final class CalendarMetaData implements CalendarMetaDataColumns, BaseColumns {
+
+ /**
+ * This utility class cannot be instantiated
+ */
+ private CalendarMetaData() {}
}
protected interface EventDaysColumns {
@@ -1746,14 +1789,12 @@
public static final class EventDays implements EventDaysColumns {
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/instances/groupbyday");
+ private static final String SELECTION = "selected=1";
/**
- * The projection used by the EventDays query.
+ * This utility class cannot be instantiated
*/
- public static final String[] PROJECTION = {
- STARTDAY, ENDDAY
- };
- private static final String SELECTION = "selected=1";
+ private EventDays() {}
/**
* Retrieves the days with events for the Julian days starting at
@@ -1765,10 +1806,12 @@
* @param cr the ContentResolver
* @param startDay the first Julian day in the range
* @param numDays the number of days to load (must be at least 1)
+ * @param projection the columns to return in the cursor
* @return a database cursor containing a list of start and end days for
* events
*/
- public static final Cursor query(ContentResolver cr, int startDay, int numDays) {
+ public static final Cursor query(ContentResolver cr, int startDay, int numDays,
+ String[] projection) {
if (numDays < 1) {
return null;
}
@@ -1776,7 +1819,7 @@
Uri.Builder builder = CONTENT_URI.buildUpon();
ContentUris.appendId(builder, startDay);
ContentUris.appendId(builder, endDay);
- return cr.query(builder.build(), PROJECTION, SELECTION,
+ return cr.query(builder.build(), projection, SELECTION,
null /* selection args */, STARTDAY);
}
}
@@ -1821,7 +1864,7 @@
/**
* Fields and helpers for accessing reminders for an event. Each row of this
* table represents a single reminder for an event. Calling
- * {@link #query(ContentResolver, long)} will return a list of reminders for
+ * {@link #query(ContentResolver, long, String[])} will return a list of reminders for
* the event with the given eventId. Both apps and sync adapters may write
* to this table. There are three writable fields and all of them must be
* included when inserting a new reminder. They are:
@@ -1833,25 +1876,26 @@
*/
public static final class Reminders implements BaseColumns, RemindersColumns, EventsColumns {
private static final String REMINDERS_WHERE = CalendarContract.Reminders.EVENT_ID + "=?";
- /**
- * The projection used by the reminders query.
- */
- public static final String[] PROJECTION = new String[] {
- _ID, MINUTES, METHOD,};
@SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/reminders");
/**
+ * This utility class cannot be instantiated
+ */
+ private Reminders() {}
+
+ /**
* Queries all reminders associated with the given event. This is a
* blocking call and should not be done on the UI thread.
*
* @param cr The content resolver to use for the query
* @param eventId The id of the event to retrieve reminders for
+ * @param projection the columns to return in the cursor
* @return A Cursor containing all reminders for the event
*/
- public static final Cursor query(ContentResolver cr, long eventId) {
+ public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
String[] remArgs = {Long.toString(eventId)};
- return cr.query(CONTENT_URI, PROJECTION, REMINDERS_WHERE, remArgs /* selection args */,
+ return cr.query(CONTENT_URI, projection, REMINDERS_WHERE, remArgs /*selection args*/,
null /* sort order */);
}
}
@@ -1964,6 +2008,11 @@
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +
"/calendar_alerts");
+ /**
+ * This utility class cannot be instantiated
+ */
+ private CalendarAlerts() {}
+
private static final String WHERE_ALARM_EXISTS = EVENT_ID + "=?"
+ " AND " + BEGIN + "=?"
+ " AND " + ALARM_TIME + "=?";
@@ -2134,7 +2183,7 @@
* given event id, begin time and alarm time. If one is found then this
* alarm already exists and this method returns true. TODO Move to
* provider
- *
+ *
* @param cr the ContentResolver
* @param eventId the event id to match
* @param begin the start time of the event in UTC millis
@@ -2203,6 +2252,11 @@
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/extendedproperties");
+ /**
+ * This utility class cannot be instantiated
+ */
+ private ExtendedProperties() {}
+
// TODO: fill out this class when we actually start utilizing extendedproperties
// in the calendar application.
}
@@ -2271,5 +2325,10 @@
* @hide
*/
public static final class EventsRawTimes implements BaseColumns, EventsRawTimesColumns {
+
+ /**
+ * This utility class cannot be instantiated
+ */
+ private EventsRawTimes() {}
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 65babc2..23b53ae 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3833,6 +3833,11 @@
/** {@hide} */
public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history";
+ /** Preferred NTP server. {@hide} */
+ public static final String NTP_SERVER = "ntp_server";
+ /** Timeout in milliseconds to wait for NTP server. {@hide} */
+ public static final String NTP_TIMEOUT = "ntp_timeout";
+
/**
* @hide
*/
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index c7603ee..8ef4295 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -384,11 +384,16 @@
}
count += written;
}
+
+ param.mLogger.onPlaybackStart();
}
private void handleSynthesisDone(MessageParams msg) {
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
handleSynthesisDone(params);
+ // This call is delayed more than it should be, but we are
+ // certain at this point that we have all the data we want.
+ params.mLogger.onWriteData();
}
// Flush all remaining data to the audio track, stop it and release
@@ -416,6 +421,8 @@
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
+ params.mLogger.onPlaybackStart();
+
// Channel config and bytes per frame are checked before
// this message is sent.
int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount);
diff --git a/core/java/android/speech/tts/EventLogTags.logtags b/core/java/android/speech/tts/EventLogTags.logtags
new file mode 100644
index 0000000..1a9f5fe
--- /dev/null
+++ b/core/java/android/speech/tts/EventLogTags.logtags
@@ -0,0 +1,6 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.speech.tts;
+
+76001 tts_speak_success (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1),(engine_latency|2|3),(engine_total|2|3),(audio_latency|2|3)
+76002 tts_speak_failure (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1)
diff --git a/core/java/android/speech/tts/EventLogger.java b/core/java/android/speech/tts/EventLogger.java
new file mode 100644
index 0000000..63b954b
--- /dev/null
+++ b/core/java/android/speech/tts/EventLogger.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.speech.tts;
+
+import android.os.SystemClock;
+import android.text.TextUtils;
+
+/**
+ * Writes data about a given speech synthesis request to the event logs.
+ * The data that is logged includes the calling app, length of the utterance,
+ * speech rate / pitch and the latency and overall time taken.
+ *
+ * Note that {@link EventLogger#onStopped()} and {@link EventLogger#onError()}
+ * might be called from any thread, but on {@link EventLogger#onPlaybackStart()} and
+ * {@link EventLogger#onComplete()} must be called from a single thread
+ * (usually the audio playback thread}
+ */
+class EventLogger {
+ private final SynthesisRequest mRequest;
+ private final String mCallingApp;
+ private final String mServiceApp;
+ private final long mReceivedTime;
+ private long mPlaybackStartTime = -1;
+ private volatile long mRequestProcessingStartTime = -1;
+ private volatile long mEngineStartTime = -1;
+ private volatile long mEngineCompleteTime = -1;
+
+ private volatile boolean mError = false;
+ private volatile boolean mStopped = false;
+ private boolean mLogWritten = false;
+
+ EventLogger(SynthesisRequest request, String callingApp,
+ String serviceApp) {
+ mRequest = request;
+ mCallingApp = callingApp;
+ mServiceApp = serviceApp;
+ mReceivedTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that this request has been selected from
+ * the processing queue for processing. Engine latency / total time
+ * is measured from this baseline.
+ */
+ public void onRequestProcessingStart() {
+ mRequestProcessingStartTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that a chunk of data has been received from
+ * the engine. Might be called multiple times.
+ */
+ public void onEngineDataReceived() {
+ if (mEngineStartTime == -1) {
+ mEngineStartTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ /**
+ * Notifies the logger that the engine has finished processing data.
+ * Will be called exactly once.
+ */
+ public void onEngineComplete() {
+ mEngineCompleteTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that audio playback has started for some section
+ * of the synthesis. This is normally some amount of time after the engine
+ * has synthesized data and varides depending on utterances and
+ * other audio currently in the queue.
+ */
+ public void onPlaybackStart() {
+ // For now, keep track of only the first chunk of audio
+ // that was played.
+ if (mPlaybackStartTime == -1) {
+ mPlaybackStartTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ /**
+ * Notifies the logger that the current synthesis was stopped.
+ * Latency numbers are not reported for stopped syntheses.
+ */
+ public void onStopped() {
+ mStopped = false;
+ }
+
+ /**
+ * Notifies the logger that the current synthesis resulted in
+ * an error. This is logged using {@link EventLogTags#writeTtsSpeakFailure}.
+ */
+ public void onError() {
+ mError = true;
+ }
+
+ /**
+ * Notifies the logger that the current synthesis has completed.
+ * All available data is not logged.
+ */
+ public void onWriteData() {
+ if (mLogWritten) {
+ return;
+ } else {
+ mLogWritten = true;
+ }
+
+ long completionTime = SystemClock.elapsedRealtime();
+ // onPlaybackStart() should normally always be called if an
+ // error does not occur.
+ if (mError || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) {
+ EventLogTags.writeTtsSpeakFailure(mServiceApp, mCallingApp,
+ getUtteranceLength(), getLocaleString(),
+ mRequest.getSpeechRate(), mRequest.getPitch());
+ return;
+ }
+
+ // We don't report stopped syntheses because their overall
+ // total time spent will be innacurate (will not correlate with
+ // the length of the utterance).
+ if (mStopped) {
+ return;
+ }
+
+ final long audioLatency = mPlaybackStartTime - mReceivedTime;
+ final long engineLatency = mEngineStartTime - mRequestProcessingStartTime;
+ final long engineTotal = mEngineCompleteTime - mRequestProcessingStartTime;
+ EventLogTags.writeTtsSpeakSuccess(mServiceApp, mCallingApp,
+ getUtteranceLength(), getLocaleString(),
+ mRequest.getSpeechRate(), mRequest.getPitch(),
+ engineLatency, engineTotal, audioLatency);
+ }
+
+ /**
+ * @return the length of the utterance for the given synthesis, 0
+ * if the utterance was {@code null}.
+ */
+ private int getUtteranceLength() {
+ final String utterance = mRequest.getText();
+ return utterance == null ? 0 : utterance.length();
+ }
+
+ /**
+ * Returns a formatted locale string from the synthesis params of the
+ * form lang-country-variant.
+ */
+ private String getLocaleString() {
+ StringBuilder sb = new StringBuilder(mRequest.getLanguage());
+ if (!TextUtils.isEmpty(mRequest.getCountry())) {
+ sb.append('-');
+ sb.append(mRequest.getCountry());
+
+ if (!TextUtils.isEmpty(mRequest.getVariant())) {
+ sb.append('-');
+ sb.append(mRequest.getVariant());
+ }
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index bdaa1b8..38030a6 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -65,29 +65,42 @@
private final UtteranceCompletedDispatcher mDispatcher;
private final String mCallingApp;
+ private final EventLogger mLogger;
PlaybackSynthesisCallback(int streamType, float volume, float pan,
AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
- String callingApp) {
+ String callingApp, EventLogger logger) {
mStreamType = streamType;
mVolume = volume;
mPan = pan;
mAudioTrackHandler = audioTrackHandler;
mDispatcher = dispatcher;
mCallingApp = callingApp;
+ mLogger = logger;
}
@Override
void stop() {
if (DBG) Log.d(TAG, "stop()");
+ // Note that mLogger.mError might be true too at this point.
+ mLogger.onStopped();
+
synchronized (mStateLock) {
- if (mToken == null || mStopped) {
- Log.w(TAG, "stop() called twice, before start(), or after done()");
+ if (mStopped) {
+ Log.w(TAG, "stop() called twice");
return;
}
- mAudioTrackHandler.stop(mToken);
- mToken = null;
+ // mToken will be null if the engine encounters
+ // an error before it called start().
+ if (mToken != null) {
+ mAudioTrackHandler.stop(mToken);
+ mToken = null;
+ } else {
+ // In all other cases, mAudioTrackHandler.stop() will
+ // result in onComplete being called.
+ mLogger.onWriteData();
+ }
mStopped = true;
}
}
@@ -124,7 +137,7 @@
}
SynthesisMessageParams params = new SynthesisMessageParams(
mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp);
+ mDispatcher, mCallingApp, mLogger);
mAudioTrackHandler.enqueueSynthesisStart(params);
mToken = params;
@@ -157,6 +170,8 @@
mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken);
}
+ mLogger.onEngineDataReceived();
+
return TextToSpeech.SUCCESS;
}
@@ -177,6 +192,7 @@
}
mAudioTrackHandler.enqueueSynthesisDone(mToken);
+ mLogger.onEngineComplete();
}
return TextToSpeech.SUCCESS;
}
@@ -184,6 +200,9 @@
@Override
public void error() {
if (DBG) Log.d(TAG, "error() [will call stop]");
+ // Currently, this call will not be logged if error( ) is called
+ // before start.
+ mLogger.onError();
stop();
}
@@ -208,7 +227,7 @@
}
SynthesisMessageParams params = new SynthesisMessageParams(
mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp);
+ mDispatcher, mCallingApp, mLogger);
params.addBuffer(buffer, offset, length);
mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 51f3d2e..caf02ef 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -30,6 +30,7 @@
final int mChannelCount;
final float mVolume;
final float mPan;
+ final EventLogger mLogger;
public volatile AudioTrack mAudioTrack;
@@ -38,7 +39,7 @@
SynthesisMessageParams(int streamType, int sampleRate,
int audioFormat, int channelCount,
float volume, float pan, UtteranceCompletedDispatcher dispatcher,
- String callingApp) {
+ String callingApp, EventLogger logger) {
super(dispatcher, callingApp);
mStreamType = streamType;
@@ -47,6 +48,7 @@
mChannelCount = channelCount;
mVolume = volume;
mPan = pan;
+ mLogger = logger;
// initially null.
mAudioTrack = null;
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 7ea9373..010c155 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -82,8 +82,7 @@
private AudioPlaybackHandler mAudioPlaybackHandler;
private CallbackMap mCallbacks;
-
- private int mDefaultAvailability = TextToSpeech.LANG_NOT_SUPPORTED;
+ private String mPackageName;
@Override
public void onCreate() {
@@ -99,9 +98,10 @@
mCallbacks = new CallbackMap();
+ mPackageName = getApplicationInfo().packageName;
+
// Load default language
- mDefaultAvailability = onLoadLanguage(getDefaultLanguage(),
- getDefaultCountry(), getDefaultVariant());
+ onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
}
@Override
@@ -457,12 +457,14 @@
// Non null after synthesis has started, and all accesses
// guarded by 'this'.
private AbstractSynthesisCallback mSynthesisCallback;
+ private final EventLogger mEventLogger;
public SynthesisSpeechItem(String callingApp, Bundle params, String text) {
super(callingApp, params);
mText = text;
mSynthesisRequest = new SynthesisRequest(mText, mParams);
setRequestParams(mSynthesisRequest);
+ mEventLogger = new EventLogger(mSynthesisRequest, getCallingApp(), mPackageName);
}
public String getText() {
@@ -485,6 +487,7 @@
@Override
protected int playImpl() {
AbstractSynthesisCallback synthesisCallback;
+ mEventLogger.onRequestProcessingStart();
synchronized (this) {
mSynthesisCallback = createSynthesisCallback();
synthesisCallback = mSynthesisCallback;
@@ -495,7 +498,7 @@
protected AbstractSynthesisCallback createSynthesisCallback() {
return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(),
- mAudioPlaybackHandler, this, getCallingApp());
+ mAudioPlaybackHandler, this, getCallingApp(), mEventLogger);
}
private void setRequestParams(SynthesisRequest request) {
diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java
new file mode 100644
index 0000000..f9920dd
--- /dev/null
+++ b/core/java/android/text/method/AllCapsTransformationMethod.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.text.method;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+
+import java.util.Locale;
+
+/**
+ * Transforms source text into an ALL CAPS string, locale-aware.
+ *
+ * @hide
+ */
+public class AllCapsTransformationMethod implements TransformationMethod2 {
+ private static final String TAG = "AllCapsTransformationMethod";
+
+ private boolean mEnabled;
+ private Locale mLocale;
+
+ public AllCapsTransformationMethod(Context context) {
+ mLocale = context.getResources().getConfiguration().locale;
+ }
+
+ @Override
+ public CharSequence getTransformation(CharSequence source, View view) {
+ if (mEnabled) {
+ return source != null ? source.toString().toUpperCase(mLocale) : null;
+ }
+ Log.w(TAG, "Caller did not enable length changes; not transforming text");
+ return source;
+ }
+
+ @Override
+ public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction,
+ Rect previouslyFocusedRect) {
+ }
+
+ @Override
+ public void setLengthChangesAllowed(boolean allowLengthChanges) {
+ mEnabled = allowLengthChanges;
+ }
+
+}
diff --git a/core/java/android/text/method/TransformationMethod2.java b/core/java/android/text/method/TransformationMethod2.java
new file mode 100644
index 0000000..ef00ecd
--- /dev/null
+++ b/core/java/android/text/method/TransformationMethod2.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.text.method;
+
+/**
+ * TransformationMethod2 extends the TransformationMethod interface
+ * and adds the ability to relax restrictions of TransformationMethod.
+ *
+ * @hide
+ */
+public interface TransformationMethod2 extends TransformationMethod {
+ /**
+ * Relax the contract of TransformationMethod to allow length changes,
+ * or revert to the length-restricted behavior.
+ *
+ * @param allowLengthChanges true to allow the transformation to change the length
+ * of the input string.
+ */
+ public void setLengthChangesAllowed(boolean allowLengthChanges);
+}
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 240ad9b..555aac5 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -22,12 +22,22 @@
import android.os.SystemClock;
import android.text.ParcelableSpan;
import android.text.TextUtils;
+import android.widget.TextView;
import java.util.Arrays;
import java.util.Locale;
/**
- * Holds suggestion candidates of words under this span.
+ * Holds suggestion candidates for the text enclosed in this span.
+ *
+ * When such a span is edited in an EditText, double tapping on the text enclosed in this span will
+ * display a popup dialog listing suggestion replacement for that text. The user can then replace
+ * the original text by one of the suggestions.
+ *
+ * These spans should typically be created by the input method to privide correction and alternates
+ * for the text.
+ *
+ * @see TextView#setSuggestionsEnabled(boolean)
*/
public class SuggestionSpan implements ParcelableSpan {
/**
@@ -115,14 +125,14 @@
}
/**
- * @return suggestions
+ * @return an array of suggestion texts for this span
*/
public String[] getSuggestions() {
return mSuggestions;
}
/**
- * @return locale of suggestions
+ * @return the locale of the suggestions
*/
public String getLocale() {
return mLocaleString;
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 5b19ecd..2179ff3 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -16,41 +16,71 @@
package android.util;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
import android.net.SntpClient;
import android.os.SystemClock;
+import android.provider.Settings;
/**
- * {@link TrustedTime} that connects with a remote NTP server as its remote
- * trusted time source.
+ * {@link TrustedTime} that connects with a remote NTP server as its trusted
+ * time source.
*
* @hide
*/
public class NtpTrustedTime implements TrustedTime {
- private String mNtpServer;
- private long mNtpTimeout;
+ private static final String TAG = "NtpTrustedTime";
+ private static final boolean LOGD = false;
+
+ private static NtpTrustedTime sSingleton;
+
+ private final String mServer;
+ private final long mTimeout;
private boolean mHasCache;
private long mCachedNtpTime;
private long mCachedNtpElapsedRealtime;
private long mCachedNtpCertainty;
- public NtpTrustedTime() {
+ private NtpTrustedTime(String server, long timeout) {
+ if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server);
+ mServer = server;
+ mTimeout = timeout;
}
- public void setNtpServer(String server, long timeout) {
- mNtpServer = server;
- mNtpTimeout = timeout;
+ public static synchronized NtpTrustedTime getInstance(Context context) {
+ if (sSingleton == null) {
+ final Resources res = context.getResources();
+ final ContentResolver resolver = context.getContentResolver();
+
+ final String defaultServer = res.getString(
+ com.android.internal.R.string.config_ntpServer);
+ final long defaultTimeout = res.getInteger(
+ com.android.internal.R.integer.config_ntpTimeout);
+
+ final String secureServer = Settings.Secure.getString(
+ resolver, Settings.Secure.NTP_SERVER);
+ final long timeout = Settings.Secure.getLong(
+ resolver, Settings.Secure.NTP_TIMEOUT, defaultTimeout);
+
+ final String server = secureServer != null ? secureServer : defaultServer;
+ sSingleton = new NtpTrustedTime(server, timeout);
+ }
+
+ return sSingleton;
}
/** {@inheritDoc} */
public boolean forceRefresh() {
- if (mNtpServer == null) {
+ if (mServer == null) {
// missing server, so no trusted time available
return false;
}
+ if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
- if (client.requestTime(mNtpServer, (int) mNtpTimeout)) {
+ if (client.requestTime(mServer, (int) mTimeout)) {
mHasCache = true;
mCachedNtpTime = client.getNtpTime();
mCachedNtpElapsedRealtime = client.getNtpTimeReference();
@@ -89,9 +119,19 @@
if (!mHasCache) {
throw new IllegalStateException("Missing authoritative time source");
}
+ if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit");
// current time is age after the last ntp cache; callers who
// want fresh values will hit makeAuthoritative() first.
return mCachedNtpTime + getCacheAge();
}
+
+ public long getCachedNtpTime() {
+ if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit");
+ return mCachedNtpTime;
+ }
+
+ public long getCachedNtpTimeReference() {
+ return mCachedNtpElapsedRealtime;
+ }
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b6c5522..4987e2f 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -246,8 +246,19 @@
return nIsBackBufferPreserved();
}
- private static native boolean nIsBackBufferPreserved();
-
+ private static native boolean nIsBackBufferPreserved();
+
+ /**
+ * Disables v-sync. For performance testing only.
+ *
+ * @hide
+ */
+ public static void disableVsync() {
+ nDisableVsync();
+ }
+
+ private static native void nDisableVsync();
+
@Override
void onPreDraw(Rect dirty) {
if (dirty != null) {
@@ -265,7 +276,7 @@
void onPostDraw() {
nFinish(mRenderer);
}
-
+
private static native void nFinish(int renderer);
@Override
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index bbfb4c1..1638c74 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -57,6 +57,16 @@
* "false", to disable partial invalidates
*/
static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions";
+
+ /**
+ * System property used to enable or disable vsync.
+ * The default value of this property is assumed to be false.
+ *
+ * Possible values:
+ * "true", to disable vsync
+ * "false", to enable vsync
+ */
+ static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
/**
* Turn on to draw dirty regions every other frame.
@@ -118,8 +128,14 @@
abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
/**
- * Setup the hardware renderer for drawing. This is called for every
- * frame to draw.
+ * Invoked whenever the size of the target surface changes. This will
+ * not be invoked when the surface is first created.
+ */
+ abstract void preapareSurfaceForResize();
+
+ /**
+ * Setup the hardware renderer for drawing. This is called whenever the
+ * size of the target surface changes or when the surface is first created.
*
* @param width Width of the drawing surface.
* @param height Height of the drawing surface.
@@ -279,9 +295,9 @@
static abstract class GlRenderer extends HardwareRenderer {
// These values are not exposed in our EGL APIs
static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- static final int EGL_SURFACE_TYPE = 0x3033;
- static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
static final int EGL_OPENGL_ES2_BIT = 4;
+ static final int EGL_SURFACE_TYPE = 0x3033;
+ static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
private static final int SURFACE_STATE_ERROR = 0;
private static final int SURFACE_STATE_SUCCESS = 1;
@@ -301,8 +317,17 @@
int mFrameCount;
Paint mDebugPaint;
- boolean mDirtyRegions;
- final boolean mDirtyRegionsRequested;
+ static boolean sDirtyRegions;
+ static final boolean sDirtyRegionsRequested;
+ static {
+ String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
+ sDirtyRegionsRequested = sDirtyRegions;
+ }
+
+ boolean mDirtyRegionsEnabled;
+ final boolean mVsyncDisabled;
final int mGlVersion;
final boolean mTranslucent;
@@ -314,17 +339,19 @@
GlRenderer(int glVersion, boolean translucent) {
mGlVersion = glVersion;
mTranslucent = translucent;
- final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
- //noinspection PointlessBooleanExpression,ConstantConditions
- mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
- mDirtyRegionsRequested = mDirtyRegions;
+
+ final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
+ mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty);
+ if (mVsyncDisabled) {
+ Log.d(LOG_TAG, "Disabling v-sync");
+ }
}
/**
* Indicates whether this renderer instance can track and update dirty regions.
*/
boolean hasDirtyRegions() {
- return mDirtyRegions;
+ return mDirtyRegionsEnabled;
}
/**
@@ -461,8 +488,8 @@
sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
// We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
- if (mDirtyRegions) {
- mDirtyRegions = false;
+ if (sDirtyRegions) {
+ sDirtyRegions = false;
sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
throw new RuntimeException("eglConfig not initialized");
@@ -482,7 +509,7 @@
private EGLConfig chooseEglConfig() {
int[] configsCount = new int[1];
EGLConfig[] configs = new EGLConfig[1];
- int[] configSpec = getConfig(mDirtyRegions);
+ int[] configSpec = getConfig(sDirtyRegions);
if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
throw new IllegalArgumentException("eglChooseConfig failed " +
getEGLErrorString(sEgl.eglGetError()));
@@ -548,18 +575,18 @@
// If mDirtyRegions is set, this means we have an EGL configuration
// with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
- if (mDirtyRegions) {
- if (!GLES20Canvas.preserveBackBuffer()) {
+ if (sDirtyRegions) {
+ if (!(mDirtyRegionsEnabled = GLES20Canvas.preserveBackBuffer())) {
Log.w(LOG_TAG, "Backbuffer cannot be preserved");
}
- } else if (mDirtyRegionsRequested) {
+ } else if (sDirtyRegionsRequested) {
// If mDirtyRegions is not set, our EGL configuration does not
// have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
// swap behavior might be EGL_BUFFER_PRESERVED, which means we
// want to set mDirtyRegions. We try to do this only if dirty
// regions were initially requested as part of the device
// configuration (see RENDER_DIRTY_REGIONS)
- mDirtyRegions = GLES20Canvas.isBackBufferPreserved();
+ mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved();
}
return sEglContext.getGL();
@@ -602,6 +629,14 @@
}
@Override
+ void preapareSurfaceForResize() {
+ // Cancels any existing buffer to ensure we'll get a buffer
+ // of the right size before we call eglSwapBuffers
+ sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ }
+
+ @Override
void setup(int width, int height) {
mCanvas.setViewport(width, height);
}
@@ -765,6 +800,14 @@
}
@Override
+ void setup(int width, int height) {
+ super.setup(width, height);
+ if (mVsyncDisabled) {
+ GLES20Canvas.disableVsync();
+ }
+ }
+
+ @Override
DisplayList createDisplayList(View v) {
return new GLES20DisplayList(v);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1245898..74dc100 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4474,7 +4474,7 @@
@RemotableViewMethod
public void setLayoutDirection(int layoutDirection) {
if (getLayoutDirection() != layoutDirection) {
- resetLayoutDirectionResolution();
+ resetResolvedLayoutDirection();
// Setting the flag will also request a layout.
setFlags(layoutDirection, LAYOUT_DIRECTION_MASK);
}
@@ -9043,10 +9043,8 @@
mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH;
}
jumpDrawablesToCurrentState();
- resetLayoutDirectionResolution();
resolveLayoutDirectionIfNeeded();
resolvePadding();
- resetResolvedTextDirection();
resolveTextDirection();
if (isFocused()) {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -9143,7 +9141,7 @@
*
* @hide
*/
- protected void resetLayoutDirectionResolution() {
+ protected void resetResolvedLayoutDirection() {
// Reset the current View resolution
mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED;
}
@@ -9190,6 +9188,9 @@
}
mCurrentAnimation = null;
+
+ resetResolvedLayoutDirection();
+ resetResolvedTextDirection();
}
/**
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index d70c798..c0619a5 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -1314,6 +1314,9 @@
if (hwInitialized || ((windowShouldResize || params != null) &&
mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled())) {
+ if (!hwInitialized) {
+ mAttachInfo.mHardwareRenderer.preapareSurfaceForResize();
+ }
mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 41412de..752fd5a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -46,7 +46,6 @@
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Locale;
/**
* <p>
@@ -5000,15 +4999,15 @@
}
@Override
- protected void resetLayoutDirectionResolution() {
- super.resetLayoutDirectionResolution();
+ protected void resetResolvedLayoutDirection() {
+ super.resetResolvedLayoutDirection();
// Take care of resetting the children resolution too
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getLayoutDirection() == LAYOUT_DIRECTION_INHERIT) {
- child.resetLayoutDirectionResolution();
+ child.resetResolvedLayoutDirection();
}
}
}
@@ -5019,7 +5018,7 @@
*/
@Override
protected void resolveTextDirection() {
- int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ int resolvedTextDirection;
switch(mTextDirection) {
default:
case TEXT_DIRECTION_INHERIT:
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index 4c42cde..f9d0067d 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -74,7 +74,8 @@
com.android.internal.R.string.autofill_country_code_re, // IDS_AUTOFILL_COUNTRY_CODE_RE
com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
- com.android.internal.R.string.autofill_phone_suffix_separator_re // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
+ com.android.internal.R.string.autofill_phone_suffix_separator_re, // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
+ com.android.internal.R.string.credit_card_number_preview_format // IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT
};
private static Context mApplicationContext;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 2145edd..c652e55 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2240,6 +2240,10 @@
}
private void setupViewport(boolean updateViewState) {
+ if (mWebView == null || mSettings == null) {
+ // We've been destroyed or are being destroyed, return early
+ return;
+ }
// set the viewport settings from WebKit
setViewportSettingsFromNative();
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 252fc8f..7d3f313 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -300,7 +300,7 @@
}
public final float getDefaultScale() {
- return mDefaultScale;
+ return mInitialScale > 0 ? mInitialScale : mDefaultScale;
}
public final float getReadingLevelScale() {
@@ -1087,6 +1087,7 @@
float scale;
if (mInitialScale > 0) {
scale = mInitialScale;
+ mTextWrapScale = scale;
} else if (viewState.mViewScale > 0) {
mTextWrapScale = viewState.mTextWrapScale;
scale = viewState.mViewScale;
@@ -1105,7 +1106,7 @@
}
boolean reflowText = false;
if (!viewState.mIsRestored) {
- if (settings.getUseFixedViewport()) {
+ if (settings.getUseFixedViewport() && mInitialScale == 0) {
// Override the scale only in case of fixed viewport.
scale = Math.max(scale, overviewScale);
mTextWrapScale = Math.max(mTextWrapScale, overviewScale);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 772e8e9..e350ec4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,11 @@
package android.widget;
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import android.R;
import android.content.ClipData;
import android.content.ClipData.Item;
@@ -62,6 +67,7 @@
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.text.method.AllCapsTransformationMethod;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.DateKeyListener;
import android.text.method.DateTimeKeyListener;
@@ -76,6 +82,7 @@
import android.text.method.TextKeyListener;
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
+import android.text.method.TransformationMethod2;
import android.text.method.WordIterator;
import android.text.style.ClickableSpan;
import android.text.style.ParagraphStyle;
@@ -125,11 +132,6 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.RemoteViews.RemoteView;
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
@@ -424,6 +426,7 @@
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
+ boolean allCaps = false;
/*
* Look the appearance up without checking first if it exists because
@@ -471,6 +474,10 @@
case com.android.internal.R.styleable.TextAppearance_textStyle:
styleIndex = appearance.getInt(attr, -1);
break;
+
+ case com.android.internal.R.styleable.TextAppearance_textAllCaps:
+ allCaps = appearance.getBoolean(attr, false);
+ break;
}
}
@@ -822,6 +829,10 @@
case com.android.internal.R.styleable.TextView_suggestionsEnabled:
mSuggestionsEnabled = a.getBoolean(attr, true);
break;
+
+ case com.android.internal.R.styleable.TextView_textAllCaps:
+ allCaps = a.getBoolean(attr, false);
+ break;
}
}
a.recycle();
@@ -1004,6 +1015,10 @@
}
setRawTextSize(textSize);
+ if (allCaps) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ }
+
if (password || passwordInputType || webPasswordInputType || numberPasswordInputType) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
typefaceIndex = MONOSPACE;
@@ -1331,6 +1346,14 @@
mTransformation = method;
+ if (method instanceof TransformationMethod2) {
+ TransformationMethod2 method2 = (TransformationMethod2) method;
+ mAllowTransformationLengthChange = !mTextIsSelectable && !(mText instanceof Editable);
+ method2.setLengthChangesAllowed(mAllowTransformationLengthChange);
+ } else {
+ mAllowTransformationLengthChange = false;
+ }
+
setText(mText);
}
@@ -1775,6 +1798,11 @@
setTypefaceByIndex(typefaceIndex, styleIndex);
+ if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
+ false)) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ }
+
appearance.recycle();
}
@@ -2823,14 +2851,15 @@
mBufferType = type;
mText = text;
- if (mTransformation == null)
+ if (mTransformation == null) {
mTransformed = text;
- else
+ } else {
mTransformed = mTransformation.getTransformation(text, this);
+ }
final int textLength = text.length();
- if (text instanceof Spannable) {
+ if (text instanceof Spannable && !mAllowTransformationLengthChange) {
Spannable sp = (Spannable) text;
// Remove any ChangeWatchers that might have come
@@ -2852,7 +2881,6 @@
if (mTransformation != null) {
sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
}
if (mMovement != null) {
@@ -5543,8 +5571,8 @@
}
@Override
- protected void resetLayoutDirectionResolution() {
- super.resetLayoutDirectionResolution();
+ protected void resetResolvedLayoutDirection() {
+ super.resetResolvedLayoutDirection();
if (mLayoutAlignment != null &&
(mTextAlign == TextAlign.VIEW_START ||
@@ -6570,6 +6598,26 @@
}
/**
+ * Sets the properties of this field to transform input to ALL CAPS
+ * display. This may use a "small caps" formatting if available.
+ * This setting will be ignored if this field is editable or selectable.
+ *
+ * This call replaces the current transformation method. Disabling this
+ * will not necessarily restore the previous behavior from before this
+ * was enabled.
+ *
+ * @see #setTransformationMethod(TransformationMethod)
+ * @attr ref android.R.styleable#TextView_textAllCaps
+ */
+ public void setAllCaps(boolean allCaps) {
+ if (allCaps) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ } else {
+ setTransformationMethod(null);
+ }
+ }
+
+ /**
* If true, sets the properties of this field (number of lines, horizontally scrolling,
* transformation method) to be for a single-line input; if false, restores these to the default
* conditions.
@@ -10254,6 +10302,7 @@
private MovementMethod mMovement;
private TransformationMethod mTransformation;
+ private boolean mAllowTransformationLengthChange;
private ChangeWatcher mChangeWatcher;
private ArrayList<TextWatcher> mListeners = null;
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 2e7ec58..b754d94 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -26,6 +26,9 @@
* codes with Message.what starting at Protocol.WIFI + 1 and less than or equal to Protocol.WIFI +
* Protocol.MAX_MESSAGE
*
+ * NOTE: After a value is created and source released a value shouldn't be changed to
+ * maintain backwards compatibility.
+ *
* {@hide}
*/
public class Protocol {
@@ -40,7 +43,7 @@
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
- public static final int BASE_DATA_CONNECTION_TRACKER = 0x00050000;
+ public static final int BASE_DATA_CONNECTION_TRACKER = 0x00042000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 3b497e4..09bebae 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -154,12 +154,7 @@
// populate accessibility description with title
setContentDescription(title);
- if (mShowTextAllCaps && title != null) {
- mTextButton.setText(title.toString().toUpperCase(
- getContext().getResources().getConfiguration().locale));
- } else {
- mTextButton.setText(mTitle);
- }
+ mTextButton.setText(mTitle);
updateTextButtonVisibility();
}
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 2f7adf0..40e5e8a 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -260,7 +260,6 @@
if (mTextView == null) {
TextView textView = new TextView(getContext(), null,
com.android.internal.R.attr.actionBarTabTextStyle);
- textView.setSingleLine();
textView.setEllipsize(TruncateAt.END);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index ddae505..d9bd50e 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -26,7 +26,7 @@
extern "C" {
int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
-int ifc_reset_connections(const char *ifname);
+int ifc_reset_connections(const char *ifname, int reset_mask);
int dhcp_do_request(const char *ifname,
const char *ipaddr,
@@ -90,12 +90,17 @@
return (jint)result;
}
-static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstring ifname)
+static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
+ jstring ifname, jint mask)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_reset_connections(nameStr);
+
+ LOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
+ env, clazz, nameStr, mask);
+
+ result = ::ifc_reset_connections(nameStr, mask);
env->ReleaseStringUTFChars(ifname, nameStr);
return (jint)result;
}
@@ -206,7 +211,7 @@
{ "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
- { "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
+ { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
{ "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2106eb4..681f43f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -115,6 +115,18 @@
return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
}
+static void android_view_GLES20Canvas_disableVsync(JNIEnv* env, jobject clazz) {
+ EGLDisplay display = eglGetCurrentDisplay();
+
+ eglGetError();
+ eglSwapInterval(display, 0);
+
+ EGLint error = eglGetError();
+ if (error != EGL_SUCCESS) {
+ RENDERER_LOGD("Could not disable v-sync (%x)", error);
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -621,7 +633,7 @@
if (layer) {
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->texture;
+ storage[0] = layer->getTexture();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -634,8 +646,8 @@
if (layer) {
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->width;
- storage[1] = layer->height;
+ storage[0] = layer->getWidth();
+ storage[1] = layer->getHeight();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -647,8 +659,8 @@
LayerRenderer::resizeLayer(layer, width, height);
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->width;
- storage[1] = layer->height;
+ storage[0] = layer->getWidth();
+ storage[1] = layer->getHeight();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -722,6 +734,7 @@
#ifdef USE_OPENGL_RENDERER
{ "nIsBackBufferPreserved", "()Z", (void*) android_view_GLES20Canvas_isBackBufferPreserved },
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
+ { "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/core/res/res/drawable-hdpi/ic_btn_back.png b/core/res/res/drawable-hdpi/ic_btn_back.png
deleted file mode 100644
index f8b3285..0000000
--- a/core/res/res/drawable-hdpi/ic_btn_back.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_next.png b/core/res/res/drawable-hdpi/ic_btn_next.png
deleted file mode 100644
index b2c6e1b..0000000
--- a/core/res/res/drawable-hdpi/ic_btn_next.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_btn_back.png b/core/res/res/drawable-mdpi/ic_btn_back.png
deleted file mode 100644
index c9bff4c..0000000
--- a/core/res/res/drawable-mdpi/ic_btn_back.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_btn_next.png b/core/res/res/drawable-mdpi/ic_btn_next.png
deleted file mode 100755
index c6cf436..0000000
--- a/core/res/res/drawable-mdpi/ic_btn_next.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/layout-sw600dp/preference_list_content.xml b/core/res/res/layout-sw600dp/preference_list_content.xml
index 5a345c6..a5320a7 100644
--- a/core/res/res/layout-sw600dp/preference_list_content.xml
+++ b/core/res/res/layout-sw600dp/preference_list_content.xml
@@ -87,7 +87,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="0"
- android:background="@android:drawable/bottom_bar"
android:visibility="gone">
<Button android:id="@+id/back_button"
@@ -95,8 +94,6 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentLeft="true"
- android:drawableLeft="@drawable/ic_btn_back"
- android:drawablePadding="3dip"
android:text="@string/back_button_label"
/>
<LinearLayout
@@ -117,8 +114,6 @@
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
- android:drawableRight="@drawable/ic_btn_next"
- android:drawablePadding="3dip"
android:text="@string/next_button_label"
/>
</LinearLayout>
diff --git a/core/res/res/layout-w600dp/preference_list_content_single.xml b/core/res/res/layout-w600dp/preference_list_content_single.xml
index 6725996..bbad296 100644
--- a/core/res/res/layout-w600dp/preference_list_content_single.xml
+++ b/core/res/res/layout-w600dp/preference_list_content_single.xml
@@ -61,7 +61,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="0"
- android:background="@android:drawable/bottom_bar"
android:visibility="gone">
<Button android:id="@+id/back_button"
@@ -69,8 +68,6 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentLeft="true"
- android:drawableLeft="@drawable/ic_btn_back"
- android:drawablePadding="3dip"
android:text="@string/back_button_label"
/>
<LinearLayout
@@ -91,8 +88,6 @@
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
- android:drawableRight="@drawable/ic_btn_next"
- android:drawablePadding="3dip"
android:text="@string/next_button_label"
/>
</LinearLayout>
diff --git a/core/res/res/layout-xlarge/activity_list.xml b/core/res/res/layout-xlarge/activity_list.xml
index ad485c1..5093a5e 100644
--- a/core/res/res/layout-xlarge/activity_list.xml
+++ b/core/res/res/layout-xlarge/activity_list.xml
@@ -54,21 +54,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
- <ImageView android:id="@+id/titleDivider"
+ <View android:id="@+id/titleDivider"
android:layout_width="match_parent"
- android:layout_height="4dip"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@android:drawable/divider_strong_holo" />
+ android:layout_height="2dip"
+ android:background="@android:color/holo_blue_light" />
<!-- If the client uses a customTitle, it will be added here. -->
</LinearLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_marginLeft="32dip"
- android:layout_marginRight="32dip"
android:layout_height="0dip"
android:layout_weight="1">
@@ -95,15 +89,12 @@
android:minHeight="54dip"
android:orientation="vertical"
android:divider="?android:attr/dividerHorizontal"
- android:showDividers="beginning"
- android:dividerPadding="16dip">
+ android:showDividers="beginning">
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingLeft="2dip"
- android:paddingRight="2dip"
android:measureWithLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
diff --git a/core/res/res/layout/activity_chooser_list_footer.xml b/core/res/res/layout/activity_chooser_list_footer.xml
index 7603a31..c05ba1a 100644
--- a/core/res/res/layout/activity_chooser_list_footer.xml
+++ b/core/res/res/layout/activity_chooser_list_footer.xml
@@ -23,13 +23,11 @@
android:gravity="center"
android:orientation="vertical">
- <ImageView
+ <View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="2dip"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@drawable/divider_strong_holo" />
+ android:background="@android:color/holo_blue_light" />
<TextView
android:id="@+id/title"
diff --git a/core/res/res/layout/activity_chooser_list_header.xml b/core/res/res/layout/activity_chooser_list_header.xml
index 867014b9..0fb256f 100644
--- a/core/res/res/layout/activity_chooser_list_header.xml
+++ b/core/res/res/layout/activity_chooser_list_header.xml
@@ -32,12 +32,10 @@
android:duplicateParentState="true"
android:singleLine="true" />
- <ImageView
+ <View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="2dip"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
android:src="@drawable/divider_strong_holo" />
</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 2185467..2b686bd 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -30,13 +30,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
- <ImageView android:id="@+id/titleDividerTop"
+ <View android:id="@+id/titleDividerTop"
android:layout_width="match_parent"
- android:layout_height="1dip"
+ android:layout_height="2dip"
android:visibility="gone"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@android:drawable/divider_strong_holo" />
+ android:background="@android:color/holo_blue_light" />
<LinearLayout android:id="@+id/title_template"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -51,20 +49,17 @@
android:paddingRight="8dip"
android:src="@null" />
<com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
- style="?android:attr/textAppearanceLarge"
- android:textColor="@android:color/holo_blue"
+ style="?android:attr/windowTitleStyle"
android:singleLine="true"
android:ellipsize="end"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
- <ImageView android:id="@+id/titleDivider"
+ <View android:id="@+id/titleDivider"
android:layout_width="match_parent"
- android:layout_height="1dip"
+ android:layout_height="2dip"
android:visibility="gone"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@android:drawable/divider_strong_holo" />
+ android:background="@android:color/holo_blue_light" />
<!-- If the client uses a customTitle, it will be added here. -->
</LinearLayout>
diff --git a/core/res/res/layout/dialog_custom_title_holo.xml b/core/res/res/layout/dialog_custom_title_holo.xml
index 5261553..e2335a7 100644
--- a/core/res/res/layout/dialog_custom_title_holo.xml
+++ b/core/res/res/layout/dialog_custom_title_holo.xml
@@ -28,12 +28,10 @@
android:gravity="center_vertical|left"
style="?android:attr/windowTitleBackgroundStyle">
</FrameLayout>
- <ImageView android:id="@+id/titleDivider"
+ <View android:id="@+id/titleDivider"
android:layout_width="match_parent"
- android:layout_height="1dip"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@android:drawable/divider_strong_holo" />
+ android:layout_height="2dip"
+ android:background="@android:color/holo_blue_light" />
<FrameLayout
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="1"
diff --git a/core/res/res/layout/dialog_title_holo.xml b/core/res/res/layout/dialog_title_holo.xml
index 400ef60..50bb0ba 100644
--- a/core/res/res/layout/dialog_title_holo.xml
+++ b/core/res/res/layout/dialog_title_holo.xml
@@ -30,12 +30,10 @@
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:gravity="center_vertical|left" />
- <ImageView android:id="@+id/titleDivider"
+ <View android:id="@+id/titleDivider"
android:layout_width="match_parent"
- android:layout_height="1dip"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@android:drawable/divider_strong_holo" />
+ android:layout_height="2dip"
+ android:background="@android:color/holo_blue_light" />
<FrameLayout
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="1"
diff --git a/core/res/res/layout/dialog_title_icons_holo.xml b/core/res/res/layout/dialog_title_icons_holo.xml
index f780ab0..7d7959f 100644
--- a/core/res/res/layout/dialog_title_icons_holo.xml
+++ b/core/res/res/layout/dialog_title_icons_holo.xml
@@ -48,12 +48,10 @@
android:layout_marginLeft="8dip" />
</LinearLayout>
- <ImageView android:id="@+id/titleDivider"
+ <View android:id="@+id/titleDivider"
android:layout_width="match_parent"
android:layout_height="1dip"
- android:scaleType="fitXY"
- android:gravity="fill_horizontal"
- android:src="@android:drawable/divider_strong_holo" />
+ android:background="@android:color/holo_blue_light" />
<FrameLayout
android:layout_width="match_parent" android:layout_height="wrap_content"
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 82b3a4c..fb898ee 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -85,7 +85,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="0"
- android:background="@android:drawable/bottom_bar"
android:visibility="gone">
<Button android:id="@+id/back_button"
@@ -93,8 +92,6 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentLeft="true"
- android:drawableLeft="@drawable/ic_btn_back"
- android:drawablePadding="3dip"
android:text="@string/back_button_label"
/>
<LinearLayout
@@ -115,8 +112,6 @@
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
- android:drawableRight="@drawable/ic_btn_next"
- android:drawablePadding="3dip"
android:text="@string/next_button_label"
/>
</LinearLayout>
diff --git a/core/res/res/layout/preference_list_content_single.xml b/core/res/res/layout/preference_list_content_single.xml
index a015761..6902ffd 100644
--- a/core/res/res/layout/preference_list_content_single.xml
+++ b/core/res/res/layout/preference_list_content_single.xml
@@ -56,7 +56,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="0"
- android:background="@android:drawable/bottom_bar"
android:visibility="gone">
<Button android:id="@+id/back_button"
@@ -64,8 +63,6 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentLeft="true"
- android:drawableLeft="@drawable/ic_btn_back"
- android:drawablePadding="3dip"
android:text="@string/back_button_label"
/>
<LinearLayout
@@ -86,8 +83,6 @@
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
- android:drawableRight="@drawable/ic_btn_next"
- android:drawablePadding="3dip"
android:text="@string/next_button_label"
/>
</LinearLayout>
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index 986536e..315f708 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
+/*
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,7 +41,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="0"
- android:background="@android:drawable/bottom_bar"
android:visibility="gone">
<Button android:id="@+id/back_button"
@@ -49,8 +48,6 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentLeft="true"
- android:drawableLeft="@drawable/ic_btn_back"
- android:drawablePadding="3dip"
android:text="@string/back_button_label"
/>
<LinearLayout
@@ -71,8 +68,6 @@
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
- android:drawableRight="@drawable/ic_btn_next"
- android:drawablePadding="3dip"
android:text="@string/next_button_label"
/>
</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2cc8171..9c2133f 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -40,6 +40,21 @@
to use accelerated drawing (thus setting state_accelerated), the
cache hint is ignored and always assumed to be transparent. -->
<attr name="colorBackgroundCacheHint" format="color" />
+
+ <!-- Default highlight color for items that are pressed. -->
+ <attr name="colorPressedHighlight" format="color" />
+ <!-- Default highlight color for items that are long-pressed. -->
+ <attr name="colorLongPressedHighlight" format="color" />
+ <!-- Default highlight color for items that are
+ focused. (Focused meaning cursor-based selection.) -->
+ <attr name="colorFocusedHighlight" format="color" />
+ <!-- Default highlight color for items that are
+ activated. (Activated meaning persistent selection.) -->
+ <attr name="colorActivatedHighlight" format="color" />
+ <!-- Default highlight color for items in multiple selection
+ mode. -->
+ <attr name="colorMultiSelectHighlight" format="color" />
+
<!-- Default disabled alpha for widgets that set enabled/disabled alpha programmatically. -->
<attr name="disabledAlpha" format="float" />
<!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
@@ -2810,6 +2825,8 @@
<attr name="textColorHint" />
<!-- Color of the links. -->
<attr name="textColorLink" />
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" format="boolean" />
</declare-styleable>
<declare-styleable name="TextSwitcher">
</declare-styleable>
@@ -3074,6 +3091,8 @@
<attr name="textIsSelectable" />
<!-- Suggestions will be displayed when the user double taps on editable text. -->
<attr name="suggestionsEnabled" />
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" />
</declare-styleable>
<!-- An <code>input-extras</code> is a container for extra data to supply to
an input method. Contains
@@ -5299,6 +5318,8 @@
<attr name="mtpReserve" format="integer" />
<!-- true if the storage can be shared via USB mass storage -->
<attr name="allowMassStorage" format="boolean" />
+ <!-- maximum file size for the volume in megabytes, zero or unspecified if it is unbounded -->
+ <attr name="maxFileSize" format="integer" />
</declare-styleable>
<declare-styleable name="SwitchPreference">
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 2a1ebfc..631d8c6 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,19 +143,42 @@
<color name="link_text_holo_light">#0000ee</color>
<!-- Group buttons -->
+ <eat-comment />
<color name="group_button_dialog_pressed_holo_dark">#46c5c1ff</color>
<color name="group_button_dialog_focused_holo_dark">#2699cc00</color>
<color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
<color name="group_button_dialog_focused_holo_light">#4699cc00</color>
+ <!-- Highlight colors for the legacy themes -->
+ <eat-comment />
+ <color name="legacy_pressed_highlight">#fffeaa0c</color>
+ <color name="legacy_selected_highlight">#fff17a0a</color>
+ <color name="legacy_long_pressed_highlight">#ffffffff</color>
+
<!-- General purpose colors for Holo-themed elements -->
<eat-comment />
- <!-- A Holo shade of blue -->
- <color name="holo_blue">#ff6699ff</color>
- <!-- A Holo shade of green -->
- <color name="holo_green">#ff99cc00</color>
+ <!-- A light Holo shade of blue -->
+ <color name="holo_blue_light">#ff33b5e5</color>
+ <!-- A light Holo shade of green -->
+ <color name="holo_green_light">#ff99cc00</color>
+ <!-- A light Holo shade of red -->
+ <color name="holo_red_light">#ffff4444</color>
+ <!-- A dark Holo shade of blue -->
+ <color name="holo_blue_dark">#ff0099cc</color>
+ <!-- A dark Holo shade of green -->
+ <color name="holo_green_dark">#ff669900</color>
+ <!-- A dark Holo shade of red -->
+ <color name="holo_red_dark">#ffcc0000</color>
+ <!-- A Holo shade of purple -->
+ <color name="holo_purple">#ffaa66cc</color>
+ <!-- A light Holo shade of orange -->
+ <color name="holo_orange_light">#ffffbb33</color>
+ <!-- A dark Holo shade of orange -->
+ <color name="holo_orange_dark">#ffff8800</color>
+ <!-- A really bright Holo shade of blue -->
+ <color name="holo_blue_bright">#ff00ddff</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9f05cbc..1f2b7fb 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -660,4 +660,9 @@
extremely limited. -->
<bool name="config_allowActionMenuItemTextWithIcon">false</bool>
+ <!-- Remote server that can provide NTP responses. -->
+ <string translatable="false" name="config_ntpServer">pool.ntp.org</string>
+ <!-- Timeout to wait for NTP server response. -->
+ <integer name="config_ntpTimeout">20000</integer>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2de9cd3..f7701f2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1779,6 +1779,14 @@
<public type="attr" name="backgroundStacked" />
<public type="attr" name="backgroundSplit" />
+ <public type="attr" name="textAllCaps" />
+
+ <public type="attr" name="colorPressedHighlight" />
+ <public type="attr" name="colorLongPressedHighlight" />
+ <public type="attr" name="colorFocusedHighlight" />
+ <public type="attr" name="colorActivatedHighlight" />
+ <public type="attr" name="colorMultiSelectHighlight" />
+
<public type="style" name="TextAppearance.SuggestionHighlight" />
<public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
<public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
@@ -1807,4 +1815,15 @@
<public type="integer" name="status_bar_notification_info_maxnum" />
<public type="string" name="status_bar_notification_info_overflow" />
+ <public type="color" name="holo_blue_light" />
+ <public type="color" name="holo_blue_dark" />
+ <public type="color" name="holo_green_light" />
+ <public type="color" name="holo_green_dark" />
+ <public type="color" name="holo_red_light" />
+ <public type="color" name="holo_red_dark" />
+ <public type="color" name="holo_orange_light" />
+ <public type="color" name="holo_orange_dark" />
+ <public type="color" name="holo_purple" />
+ <public type="color" name="holo_blue_bright" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 50f8df7..97a8c0b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2085,6 +2085,10 @@
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_suffix_separator_re">^-$</string>
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <!-- Ex: ************1234 -->
+ <string name="credit_card_number_preview_format">$1</string>
+
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 11016f4..a5cd6e3 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1319,6 +1319,7 @@
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">?android:attr/actionMenuTextColor</item>
+ <item name="android:textAllCaps">true</item>
</style>
<style name="TextAppearance.Holo.Widget.ActionMode">
@@ -1355,7 +1356,7 @@
<style name="TextAppearance.Holo.DialogWindowTitle">
<item name="android:textSize">22sp</item>
- <item name="android:textColor">@android:color/holo_blue</item>
+ <item name="android:textColor">@android:color/holo_blue_light</item>
</style>
<style name="TextAppearance.Holo.CalendarViewWeekDayView" parent="TextAppearance.Small.CalendarViewWeekDayView">
@@ -1454,7 +1455,7 @@
<style name="TextAppearance.Holo.Light.DialogWindowTitle">
<item name="android:textSize">22sp</item>
- <item name="android:textColor">@android:color/holo_blue</item>
+ <item name="android:textColor">@android:color/holo_blue_light</item>
</style>
<style name="TextAppearance.Holo.Light.CalendarViewWeekDayView" parent="TextAppearance.Small.CalendarViewWeekDayView">
@@ -1857,6 +1858,7 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
+ <item name="android:textAllCaps">true</item>
</style>
<style name="Widget.Holo.ActionMode" parent="Widget.ActionMode">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 9a52cff..90f3602 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -31,6 +31,13 @@
<item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverse</item>
<item name="colorBackground">@android:color/background_dark</item>
<item name="colorBackgroundCacheHint">?android:attr/colorBackground</item>
+
+ <item name="colorPressedHighlight">@color/legacy_pressed_highlight</item>
+ <item name="colorLongPressedHighlight">@color/legacy_long_pressed_highlight</item>
+ <item name="colorFocusedHighlight">@color/legacy_selected_highlight</item>
+ <item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item>
+ <item name="colorActivatedHighlight">@color/legacy_selected_highlight</item>
+
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
@@ -799,6 +806,12 @@
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
+ <item name="colorPressedHighlight">@color/holo_blue_light</item>
+ <item name="colorLongPressedHighlight">@color/holo_blue_bright</item>
+ <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
+ <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
+ <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
+
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.Holo</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Inverse</item>
@@ -1090,6 +1103,11 @@
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
+ <item name="colorPressedHighlight">@color/holo_blue_light</item>
+ <item name="colorLongPressedHighlight">@color/holo_blue_bright</item>
+ <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
+ <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
+ <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 8e2d925..40fa552 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1051,6 +1051,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.TextViewTestActivity" android:label="TextViewTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<!-- Activity-level metadata -->
diff --git a/core/tests/coretests/res/layout/textview_test.xml b/core/tests/coretests/res/layout/textview_test.xml
new file mode 100644
index 0000000..f0c7b9e
--- /dev/null
+++ b/core/tests/coretests/res/layout/textview_test.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/textviewtest_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView android:id="@+id/textviewtest_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/textview_hebrew_text"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index f51b08e..71f3520 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -129,4 +129,6 @@
<string name="button8">Button8</string>
<string name="button9">Button9</string>
+ <string name="textview_hebrew_text">םמab?!</string>
+
</resources>
diff --git a/core/tests/coretests/src/android/pim/EventRecurrenceTest.java b/core/tests/coretests/src/android/pim/EventRecurrenceTest.java
deleted file mode 100644
index 05000f1..0000000
--- a/core/tests/coretests/src/android/pim/EventRecurrenceTest.java
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.pim.EventRecurrence.InvalidFormatException;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-
-/**
- * Test android.pim.EventRecurrence.
- *
- * adb shell am instrument -w -e class android.pim.EventRecurrenceTest \
- * com.android.frameworks.coretests/android.test.InstrumentationTestRunner
- */
-public class EventRecurrenceTest extends TestCase {
-
- @SmallTest
- public void test0() throws Exception {
- verifyRecurType("FREQ=SECONDLY",
- /* int freq */ EventRecurrence.SECONDLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test1() throws Exception {
- verifyRecurType("FREQ=MINUTELY",
- /* int freq */ EventRecurrence.MINUTELY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test2() throws Exception {
- verifyRecurType("FREQ=HOURLY",
- /* int freq */ EventRecurrence.HOURLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test3() throws Exception {
- verifyRecurType("FREQ=DAILY",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test4() throws Exception {
- verifyRecurType("FREQ=WEEKLY",
- /* int freq */ EventRecurrence.WEEKLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test5() throws Exception {
- verifyRecurType("FREQ=MONTHLY",
- /* int freq */ EventRecurrence.MONTHLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test6() throws Exception {
- verifyRecurType("FREQ=YEARLY",
- /* int freq */ EventRecurrence.YEARLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test7() throws Exception {
- // with an until
- verifyRecurType("FREQ=DAILY;UNTIL=112233T223344Z",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ "112233T223344Z",
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test8() throws Exception {
- // with a count
- verifyRecurType("FREQ=DAILY;COUNT=334",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 334,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test9() throws Exception {
- // with a count
- verifyRecurType("FREQ=DAILY;INTERVAL=5000",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 5000,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test10() throws Exception {
- // verifyRecurType all of the BY* ones with one element
- verifyRecurType("FREQ=DAILY"
- + ";BYSECOND=0"
- + ";BYMINUTE=1"
- + ";BYHOUR=2"
- + ";BYMONTHDAY=30"
- + ";BYYEARDAY=300"
- + ";BYWEEKNO=53"
- + ";BYMONTH=12"
- + ";BYSETPOS=-15"
- + ";WKST=SU",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ new int[]{0},
- /* int[] byminute */ new int[]{1},
- /* int[] byhour */ new int[]{2},
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ new int[]{30},
- /* int[] byyearday */ new int[]{300},
- /* int[] byweekno */ new int[]{53},
- /* int[] bymonth */ new int[]{12},
- /* int[] bysetpos */ new int[]{-15},
- /* int wkst */ EventRecurrence.SU
- );
- }
-
- @SmallTest
- public void test11() throws Exception {
- // verifyRecurType all of the BY* ones with one element
- verifyRecurType("FREQ=DAILY"
- + ";BYSECOND=0,30,59"
- + ";BYMINUTE=0,41,59"
- + ";BYHOUR=0,4,23"
- + ";BYMONTHDAY=-31,-1,1,31"
- + ";BYYEARDAY=-366,-1,1,366"
- + ";BYWEEKNO=-53,-1,1,53"
- + ";BYMONTH=1,12"
- + ";BYSETPOS=1,2,3,4,500,10000"
- + ";WKST=SU",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ new int[]{0, 30, 59},
- /* int[] byminute */ new int[]{0, 41, 59},
- /* int[] byhour */ new int[]{0, 4, 23},
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ new int[]{-31, -1, 1, 31},
- /* int[] byyearday */ new int[]{-366, -1, 1, 366},
- /* int[] byweekno */ new int[]{-53, -1, 1, 53},
- /* int[] bymonth */ new int[]{1, 12},
- /* int[] bysetpos */ new int[]{1, 2, 3, 4, 500, 10000},
- /* int wkst */ EventRecurrence.SU
- );
- }
-
- private static class Check {
- Check(String k, int... v) {
- key = k;
- values = v;
- }
-
- String key;
- int[] values;
- }
-
- // this is a negative verifyRecurType case to verifyRecurType the range of the numbers accepted
- @SmallTest
- public void test12() throws Exception {
- Check[] checks = new Check[]{
- new Check("BYSECOND", -100, -1, 60, 100),
- new Check("BYMINUTE", -100, -1, 60, 100),
- new Check("BYHOUR", -100, -1, 24, 100),
- new Check("BYMONTHDAY", -100, -32, 0, 32, 100),
- new Check("BYYEARDAY", -400, -367, 0, 367, 400),
- new Check("BYWEEKNO", -100, -54, 0, 54, 100),
- new Check("BYMONTH", -100, -5, 0, 13, 100)
- };
-
- for (Check ck : checks) {
- for (int n : ck.values) {
- String recur = "FREQ=DAILY;" + ck.key + "=" + n;
- try {
- EventRecurrence er = new EventRecurrence();
- er.parse(recur);
- fail("Negative verifyRecurType failed. "
- + " parse failed to throw an exception for '"
- + recur + "'");
- } catch (EventRecurrence.InvalidFormatException e) {
- // expected
- }
- }
- }
- }
-
- // verifyRecurType BYDAY
- @SmallTest
- public void test13() throws Exception {
- verifyRecurType("FREQ=DAILY;BYDAY=1SU,-2MO,+33TU,WE,TH,FR,SA",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.SU,
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- EventRecurrence.TH,
- EventRecurrence.FR,
- EventRecurrence.SA
- },
- /* int[] bydayNum */ new int[]{1, -2, 33, 0, 0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @Suppress
- // Repro bug #2331761 - this should fail because of the last comma into BYDAY
- public void test14() throws Exception {
- verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;BYDAY=MO,TU,WE,",
- /* int freq */ EventRecurrence.WEEKLY,
- /* String until */ "20100129T130000Z",
- /* int count */ 0,
- /* int interval */ 1,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- },
- /* int[] bydayNum */ new int[]{0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // This test should pass
- public void test15() throws Exception {
- verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;"
- + "BYDAY=MO,TU,WE,TH,FR,SA,SU",
- /* int freq */ EventRecurrence.WEEKLY,
- /* String until */ "20100129T130000Z",
- /* int count */ 0,
- /* int interval */ 1,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- EventRecurrence.TH,
- EventRecurrence.FR,
- EventRecurrence.SA,
- EventRecurrence.SU
- },
- /* int[] bydayNum */ new int[]{0, 0, 0, 0, 0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from RFC2445
- public void test16() throws Exception {
- verifyRecurType("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1",
- /* int freq */ EventRecurrence.MONTHLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- EventRecurrence.TH,
- EventRecurrence.FR
- },
- /* int[] bydayNum */ new int[] {0, 0, 0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ new int[] { -1 },
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from RFC2445
- public void test17() throws Exception {
- verifyRecurType("FREQ=DAILY;COUNT=10;INTERVAL=2",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 10,
- /* int interval */ 2,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from RFC2445
- public void test18() throws Exception {
- verifyRecurType("FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10",
- /* int freq */ EventRecurrence.YEARLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.SU
- },
- /* int[] bydayNum */ new int[] { -1 },
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ new int[] { 10 },
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from bug #1640517
- public void test19() throws Exception {
- verifyRecurType("FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
- /* int freq */ EventRecurrence.YEARLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.TH
- },
- /* int[] bydayNum */ new int[] { 0 },
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ new int[] { 3 },
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // for your copying pleasure
- public void fakeTestXX() throws Exception {
- verifyRecurType("FREQ=DAILY;",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- private static void cmp(int vlen, int[] v, int[] correct, String name) {
- if ((correct == null && v != null)
- || (correct != null && v == null)) {
- throw new RuntimeException("One is null, one isn't for " + name
- + ": correct=" + Arrays.toString(correct)
- + " actual=" + Arrays.toString(v));
- }
- if ((correct == null && vlen != 0)
- || (vlen != (correct == null ? 0 : correct.length))) {
- throw new RuntimeException("Reported length mismatch for " + name
- + ": correct=" + ((correct == null) ? "null" : correct.length)
- + " actual=" + vlen);
- }
- if (correct == null) {
- return;
- }
- if (v.length < correct.length) {
- throw new RuntimeException("Array length mismatch for " + name
- + ": correct=" + Arrays.toString(correct)
- + " actual=" + Arrays.toString(v));
- }
- for (int i = 0; i < correct.length; i++) {
- if (v[i] != correct[i]) {
- throw new RuntimeException("Array value mismatch for " + name
- + ": correct=" + Arrays.toString(correct)
- + " actual=" + Arrays.toString(v));
- }
- }
- }
-
- private static boolean eq(String a, String b) {
- if ((a == null && b != null) || (a != null && b == null)) {
- return false;
- } else {
- return a == b || a.equals(b);
- }
- }
-
- private static void verifyRecurType(String recur,
- int freq, String until, int count, int interval,
- int[] bysecond, int[] byminute, int[] byhour,
- int[] byday, int[] bydayNum, int[] bymonthday,
- int[] byyearday, int[] byweekno, int[] bymonth,
- int[] bysetpos, int wkst) {
- EventRecurrence eventRecurrence = new EventRecurrence();
- eventRecurrence.parse(recur);
- if (eventRecurrence.freq != freq
- || !eq(eventRecurrence.until, until)
- || eventRecurrence.count != count
- || eventRecurrence.interval != interval
- || eventRecurrence.wkst != wkst) {
- System.out.println("Error... got:");
- print(eventRecurrence);
- System.out.println("expected:");
- System.out.println("{");
- System.out.println(" freq=" + freq);
- System.out.println(" until=" + until);
- System.out.println(" count=" + count);
- System.out.println(" interval=" + interval);
- System.out.println(" wkst=" + wkst);
- System.out.println(" bysecond=" + Arrays.toString(bysecond));
- System.out.println(" byminute=" + Arrays.toString(byminute));
- System.out.println(" byhour=" + Arrays.toString(byhour));
- System.out.println(" byday=" + Arrays.toString(byday));
- System.out.println(" bydayNum=" + Arrays.toString(bydayNum));
- System.out.println(" bymonthday=" + Arrays.toString(bymonthday));
- System.out.println(" byyearday=" + Arrays.toString(byyearday));
- System.out.println(" byweekno=" + Arrays.toString(byweekno));
- System.out.println(" bymonth=" + Arrays.toString(bymonth));
- System.out.println(" bysetpos=" + Arrays.toString(bysetpos));
- System.out.println("}");
- throw new RuntimeException("Mismatch in fields");
- }
- cmp(eventRecurrence.bysecondCount, eventRecurrence.bysecond, bysecond, "bysecond");
- cmp(eventRecurrence.byminuteCount, eventRecurrence.byminute, byminute, "byminute");
- cmp(eventRecurrence.byhourCount, eventRecurrence.byhour, byhour, "byhour");
- cmp(eventRecurrence.bydayCount, eventRecurrence.byday, byday, "byday");
- cmp(eventRecurrence.bydayCount, eventRecurrence.bydayNum, bydayNum, "bydayNum");
- cmp(eventRecurrence.bymonthdayCount, eventRecurrence.bymonthday, bymonthday, "bymonthday");
- cmp(eventRecurrence.byyeardayCount, eventRecurrence.byyearday, byyearday, "byyearday");
- cmp(eventRecurrence.byweeknoCount, eventRecurrence.byweekno, byweekno, "byweekno");
- cmp(eventRecurrence.bymonthCount, eventRecurrence.bymonth, bymonth, "bymonth");
- cmp(eventRecurrence.bysetposCount, eventRecurrence.bysetpos, bysetpos, "bysetpos");
- }
-
- private static void print(EventRecurrence er) {
- System.out.println("{");
- System.out.println(" freq=" + er.freq);
- System.out.println(" until=" + er.until);
- System.out.println(" count=" + er.count);
- System.out.println(" interval=" + er.interval);
- System.out.println(" wkst=" + er.wkst);
- System.out.println(" bysecond=" + Arrays.toString(er.bysecond));
- System.out.println(" bysecondCount=" + er.bysecondCount);
- System.out.println(" byminute=" + Arrays.toString(er.byminute));
- System.out.println(" byminuteCount=" + er.byminuteCount);
- System.out.println(" byhour=" + Arrays.toString(er.byhour));
- System.out.println(" byhourCount=" + er.byhourCount);
- System.out.println(" byday=" + Arrays.toString(er.byday));
- System.out.println(" bydayNum=" + Arrays.toString(er.bydayNum));
- System.out.println(" bydayCount=" + er.bydayCount);
- System.out.println(" bymonthday=" + Arrays.toString(er.bymonthday));
- System.out.println(" bymonthdayCount=" + er.bymonthdayCount);
- System.out.println(" byyearday=" + Arrays.toString(er.byyearday));
- System.out.println(" byyeardayCount=" + er.byyeardayCount);
- System.out.println(" byweekno=" + Arrays.toString(er.byweekno));
- System.out.println(" byweeknoCount=" + er.byweeknoCount);
- System.out.println(" bymonth=" + Arrays.toString(er.bymonth));
- System.out.println(" bymonthCount=" + er.bymonthCount);
- System.out.println(" bysetpos=" + Arrays.toString(er.bysetpos));
- System.out.println(" bysetposCount=" + er.bysetposCount);
- System.out.println("}");
- }
-
-
- /** A list of valid rules. The parser must accept these. */
- private static final String[] GOOD_RRULES = {
- /* extracted wholesale from from RFC 2445 section 4.8.5.4 */
- "FREQ=DAILY;COUNT=10",
- "FREQ=DAILY;UNTIL=19971224T000000Z",
- "FREQ=DAILY;INTERVAL=2",
- "FREQ=DAILY;INTERVAL=10;COUNT=5",
- "FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA",
- "FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1",
- "FREQ=WEEKLY;COUNT=10",
- "FREQ=WEEKLY;UNTIL=19971224T000000Z",
- "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
- "FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH",
- "FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH",
- "FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH",
- "FREQ=MONTHLY;COUNT=10;BYDAY=1FR",
- "FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR",
- "FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU",
- "FREQ=MONTHLY;COUNT=6;BYDAY=-2MO",
- "FREQ=MONTHLY;BYMONTHDAY=-3",
- "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15",
- "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1",
- "FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15",
- "FREQ=MONTHLY;INTERVAL=2;BYDAY=TU",
- "FREQ=YEARLY;COUNT=10;BYMONTH=6,7",
- "FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3",
- "FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200",
- "FREQ=YEARLY;BYDAY=20MO",
- "FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO",
- "FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
- "FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8",
- "FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13",
- "FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13",
- "FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8",
- "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3",
- "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2",
- "FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z",
- "FREQ=MINUTELY;INTERVAL=15;COUNT=6",
- "FREQ=MINUTELY;INTERVAL=90;COUNT=4",
- "FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40",
- "FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU",
- /* a few more */
- "FREQ=SECONDLY;BYSECOND=0,15,59",
- "FREQ=MINUTELY;BYMINUTE=0,15,59",
- "FREQ=HOURLY;BYHOUR=+0,+15,+23",
- "FREQ=DAILY;X-WHATEVER=blah", // fails on old parser
- //"freq=daily;wkst=su", // fails on old parser
- };
-
- /** The parser must reject these. */
- private static final String[] BAD_RRULES = {
- "INTERVAL=4;FREQ=YEARLY", // FREQ must come first
- "FREQ=MONTHLY;FREQ=MONTHLY", // can't specify twice
- "FREQ=MONTHLY;COUNT=1;COUNT=1", // can't specify twice
- "FREQ=SECONDLY;BYSECOND=60", // range
- "FREQ=MINUTELY;BYMINUTE=-1", // range
- "FREQ=HOURLY;BYHOUR=24", // range
- "FREQ=YEARLY;BYMONTHDAY=0", // zero not valid
- //"FREQ=YEARLY;COUNT=1;UNTIL=12345", // can't have both COUNT and UNTIL
- //"FREQ=DAILY;UNTIL=19970829T021400e", // invalid date
- };
-
- /**
- * Simple test of good/bad rules.
- */
- @SmallTest
- public void testBasicParse() {
- for (String rule : GOOD_RRULES) {
- EventRecurrence recur = new EventRecurrence();
- recur.parse(rule);
- }
-
- for (String rule : BAD_RRULES) {
- EventRecurrence recur = new EventRecurrence();
- boolean didThrow = false;
-
- try {
- recur.parse(rule);
- } catch (InvalidFormatException ife) {
- didThrow = true;
- }
-
- assertTrue("Expected throw on " + rule, didThrow);
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/RecurrenceSetTest.java b/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
deleted file mode 100644
index e5ab179..0000000
--- a/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.content.ContentValues;
-import android.pim.ICalendar;
-import android.pim.RecurrenceSet;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-import android.provider.CalendarContract;
-import junit.framework.TestCase;
-
-/**
- * Test some pim.RecurrenceSet functionality.
- */
-public class RecurrenceSetTest extends TestCase {
-
- // Test a recurrence
- @SmallTest
- public void testRecurrenceSet0() throws Exception {
- String recurrence = "DTSTART;TZID=America/New_York:20080221T070000\n"
- + "DTEND;TZID=America/New_York:20080221T190000\n"
- + "RRULE:FREQ=DAILY;UNTIL=20080222T000000Z\n"
- + "EXDATE:20080222T120000Z";
- verifyPopulateContentValues(recurrence, "FREQ=DAILY;UNTIL=20080222T000000Z", null,
- null, "20080222T120000Z", 1203595200000L, "America/New_York", "P43200S", 0);
- }
-
- // Test 1 day all-day event
- @SmallTest
- public void testRecurrenceSet1() throws Exception {
- String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090822\n"
- + "RRULE:FREQ=YEARLY;WKST=SU";
- verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
- null, null, 1250812800000L, "UTC", "P1D", 1);
- }
-
- // Test 2 day all-day event
- @SmallTest
- public void testRecurrenceSet2() throws Exception {
- String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090823\n"
- + "RRULE:FREQ=YEARLY;WKST=SU";
- verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
- null, null, 1250812800000L, "UTC", "P2D", 1);
- }
-
- // run populateContentValues and verify the results
- private void verifyPopulateContentValues(String recurrence, String rrule, String rdate,
- String exrule, String exdate, long dtstart, String tzid, String duration, int allDay)
- throws ICalendar.FormatException {
- ICalendar.Component recurrenceComponent =
- new ICalendar.Component("DUMMY", null /* parent */);
- ICalendar.parseComponent(recurrenceComponent, recurrence);
- ContentValues values = new ContentValues();
- RecurrenceSet.populateContentValues(recurrenceComponent, values);
- Log.d("KS", "values " + values);
-
- assertEquals(rrule, values.get(android.provider.CalendarContract.Events.RRULE));
- assertEquals(rdate, values.get(android.provider.CalendarContract.Events.RDATE));
- assertEquals(exrule, values.get(android.provider.CalendarContract.Events.EXRULE));
- assertEquals(exdate, values.get(android.provider.CalendarContract.Events.EXDATE));
- assertEquals(dtstart, (long) values.getAsLong(CalendarContract.Events.DTSTART));
- assertEquals(tzid, values.get(android.provider.CalendarContract.Events.EVENT_TIMEZONE));
- assertEquals(duration, values.get(android.provider.CalendarContract.Events.DURATION));
- assertEquals(allDay,
- (int) values.getAsInteger(android.provider.CalendarContract.Events.ALL_DAY));
- }
-}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 6db67c0..c54e4a1 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,23 +16,25 @@
package android.widget;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import com.android.frameworks.coretests.R;
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.GetChars;
import android.view.View;
-import android.widget.TextView;
/**
* TextViewTest tests {@link TextView}.
*/
-public class TextViewTest extends AndroidTestCase {
+public class TextViewTest extends ActivityInstrumentationTestCase2<TextViewTestActivity> {
+
+ public TextViewTest() {
+ super(TextViewTestActivity.class);
+ }
@SmallTest
public void testArray() throws Exception {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ',
'W', 'o', 'r', 'l', 'd', '!' };
@@ -62,13 +64,13 @@
@SmallTest
public void testTextDirectionDefault() {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
assertEquals(View.TEXT_DIRECTION_INHERIT, tv.getTextDirection());
}
@SmallTest
public void testSetGetTextDirection() {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
@@ -88,7 +90,7 @@
@SmallTest
public void testGetResolvedTextDirectionLtr() {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
tv.setText("this is a test");
tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
@@ -109,10 +111,10 @@
@SmallTest
public void testGetResolvedTextDirectionLtrWithInheritance() {
- LinearLayout ll = new LinearLayout(mContext);
+ LinearLayout ll = new LinearLayout(getActivity());
ll.setTextDirection(View.TEXT_DIRECTION_RTL);
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
tv.setText("this is a test");
ll.addView(tv);
@@ -134,7 +136,7 @@
@SmallTest
public void testGetResolvedTextDirectionRtl() {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
tv.setText("\u05DD\u05DE"); // hebrew
tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
@@ -155,10 +157,9 @@
@SmallTest
public void testGetResolvedTextDirectionRtlWithInheritance() {
- LinearLayout ll = new LinearLayout(mContext);
- ll.setTextDirection(View.TEXT_DIRECTION_RTL);
+ LinearLayout ll = new LinearLayout(getActivity());
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
tv.setText("\u05DD\u05DE"); // hebrew
ll.addView(tv);
@@ -169,6 +170,24 @@
assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
+ assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_LTR);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ // Force to RTL text direction on the layout
+ ll.setTextDirection(View.TEXT_DIRECTION_RTL);
+
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
tv.setTextDirection(View.TEXT_DIRECTION_LTR);
@@ -180,10 +199,10 @@
@SmallTest
public void testCharCountHeuristic() {
- LinearLayout ll = new LinearLayout(mContext);
+ LinearLayout ll = new LinearLayout(getActivity());
ll.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
ll.addView(tv);
tv.setTextDirection(View.TEXT_DIRECTION_CHAR_COUNT);
@@ -211,4 +230,23 @@
tv.setText("ab \u05DD\u05DE"); // latin + hebrew at 50% each
assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
}
+
+ @SmallTest
+ public void testResetTextDirection() {
+ final TextViewTestActivity activity = getActivity();
+
+ final LinearLayout ll = (LinearLayout) activity.findViewById(R.id.textviewtest_layout);
+ final TextView tv = (TextView) activity.findViewById(R.id.textviewtest_textview);
+
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+ assertEquals(true, tv.isResolvedTextDirection());
+
+ ll.removeView(tv);
+ assertEquals(false, tv.isResolvedTextDirection());
+ }
+ });
+ }
}
diff --git a/core/tests/coretests/src/android/widget/TextViewTestActivity.java b/core/tests/coretests/src/android/widget/TextViewTestActivity.java
new file mode 100644
index 0000000..1bb4d24
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/TextViewTestActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+public class TextViewTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.textview_test);
+ }
+}
diff --git a/docs/html/index.jd b/docs/html/index.jd
index eeeedd0..dce46f9 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -148,19 +148,18 @@
'tv': {
'layout':"imgLeft",
- 'icon':"tv_s.png",
+ 'icon':"GTV_icon_small.png",
'name':"Google TV",
- 'img':"tv_l.png",
- 'title':"Announcing Google TV!",
- 'desc': "<p><a href='http://www.google.com/tv/'>Google TV</a> is a new platform "
- + "for television built on Android. Google "
- + "has partnered with Sony and Logitech to integrate "
- + "this platform into TVs, blu-ray players, and companion "
- + "boxes. </p>"
- + "<p><a href='http://www.google.com/tv/'>Learn more about "
- + "Google TV »</a></p>"
+ 'img':"GTV_icon_large.png",
+ 'title':"Google TV!",
+ 'desc': "<p>Build something big. By big, we mean <em>worthy-of-the-living-room</em> big.</p>"
+ + " <p>Use <a href='http://code.google.com/tv'>Google TV</a> to bring the power of Android"
+ + " and Google Chrome to television."
+ + " The average American watches five hours of TV per day. Give them the web and apps"
+ + " to update their status, listen to music, watch web videos, and much more...</p>"
},
+
'devphone': {
'layout':"imgLeft",
'icon':"devphone-small.png",
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index b4f1b27..18f47a6 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -99,7 +99,7 @@
<a href="#" onclick="return toggleDiv(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
width="9px" />
-ADT 12.0.0</a> <em>(June 2011)</em>
+ADT 12.0.0</a> <em>(July 2011)</em>
<div class="toggleme">
<dl>
diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd
index d4ebf8a..8c4d037 100644
--- a/docs/html/sdk/tools-notes.jd
+++ b/docs/html/sdk/tools-notes.jd
@@ -66,7 +66,7 @@
<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 12</a> <em>(June 2011)</em>
+SDK Tools, Revision 12</a> <em>(July 2011)</em>
<div class="toggleme">
<dl>
<dt>Dependencies:</dt>
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 1324431..c5d7500 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -40,6 +40,7 @@
*/
public Region rects;
private boolean mDetectSimplePaths;
+ private Direction mLastDirection = null;
/**
* Create an empty path
@@ -70,6 +71,7 @@
public void reset() {
isSimplePath = true;
if (mDetectSimplePaths) {
+ mLastDirection = null;
if (rects != null) rects.setEmpty();
}
native_reset(mNativePath);
@@ -82,6 +84,7 @@
public void rewind() {
isSimplePath = true;
if (mDetectSimplePaths) {
+ mLastDirection = null;
if (rects != null) rects.setEmpty();
}
native_rewind(mNativePath);
@@ -378,6 +381,20 @@
final int nativeInt;
}
+ private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
+ if (mDetectSimplePaths) {
+ if (mLastDirection == null) {
+ mLastDirection = dir;
+ }
+ if (mLastDirection != dir) {
+ isSimplePath = false;
+ } else {
+ if (rects == null) rects = new Region();
+ rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION);
+ }
+ }
+ }
+
/**
* Add a closed rectangle contour to the path
*
@@ -388,11 +405,7 @@
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
- if (mDetectSimplePaths) {
- if (rects == null) rects = new Region();
- rects.op((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom,
- Region.Op.UNION);
- }
+ detectSimplePath(rect.left, rect.top, rect.right, rect.bottom, dir);
native_addRect(mNativePath, rect, dir.nativeInt);
}
@@ -406,10 +419,7 @@
* @param dir The direction to wind the rectangle's contour
*/
public void addRect(float left, float top, float right, float bottom, Direction dir) {
- if (mDetectSimplePaths) {
- if (rects == null) rects = new Region();
- rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION);
- }
+ detectSimplePath(left, top, right, bottom, dir);
native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
}
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index f865753..90f959f 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -95,7 +95,7 @@
// E.g, /system/apps/Fountain.apk
//String packageName = rs.getApplicationContext().getPackageResourcePath();
// For res/raw/fountain.bc, it wil be /com.android.fountain:raw/fountain
- String resName = resources.getResourceName(resourceID);
+ String resName = resources.getResourceEntryName(resourceID);
String cacheDir = rs.getApplicationContext().getCacheDir().toString();
Log.v(TAG, "Create script for resource = " + resName);
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 0310bc3..3c2d80d 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -27,6 +27,7 @@
#include "Rect.h"
#include "SkiaColorFilter.h"
+#include "Texture.h"
#include "Vertex.h"
namespace android {
@@ -40,14 +41,18 @@
* A layer has dimensions and is backed by an OpenGL texture or FBO.
*/
struct Layer {
- Layer(const uint32_t layerWidth, const uint32_t layerHeight):
- width(layerWidth), height(layerHeight) {
+ Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
mesh = NULL;
meshIndices = NULL;
meshElementCount = 0;
- isCacheable = true;
- isTextureLayer = false;
+ cacheable = true;
+ textureLayer = false;
renderTarget = GL_TEXTURE_2D;
+ texture.width = layerWidth;
+ texture.height = layerHeight;
+ colorFilter = NULL;
+ firstFilter = true;
+ firstWrap = true;
}
~Layer() {
@@ -64,12 +69,152 @@
regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
bounds.rightBottom().x, bounds.rightBottom().y);
- const float texX = 1.0f / float(width);
- const float texY = 1.0f / float(height);
+ const float texX = 1.0f / float(texture.width);
+ const float texY = 1.0f / float(texture.height);
const float height = layer.getHeight();
texCoords.set(
regionRect.left * texX, (height - regionRect.top) * texY,
regionRect.right * texX, (height - regionRect.bottom) * texY);
+
+ regionRect.translate(layer.left, layer.top);
+ }
+
+ inline uint32_t getWidth() {
+ return texture.width;
+ }
+
+ inline uint32_t getHeight() {
+ return texture.height;
+ }
+
+ void setSize(uint32_t width, uint32_t height) {
+ texture.width = width;
+ texture.height = height;
+ }
+
+ inline void setBlend(bool blend) {
+ texture.blend = blend;
+ }
+
+ inline bool isBlend() {
+ return texture.blend;
+ }
+
+ inline void setAlpha(int alpha) {
+ this->alpha = alpha;
+ }
+
+ inline void setAlpha(int alpha, SkXfermode::Mode mode) {
+ this->alpha = alpha;
+ this->mode = mode;
+ }
+
+ inline int getAlpha() {
+ return alpha;
+ }
+
+ inline SkXfermode::Mode getMode() {
+ return mode;
+ }
+
+ inline void setEmpty(bool empty) {
+ this->empty = empty;
+ }
+
+ inline bool isEmpty() {
+ return empty;
+ }
+
+ inline void setFbo(GLuint fbo) {
+ this->fbo = fbo;
+ }
+
+ inline GLuint getFbo() {
+ return fbo;
+ }
+
+ inline GLuint* getTexturePointer() {
+ return &texture.id;
+ }
+
+ inline GLuint getTexture() {
+ return texture.id;
+ }
+
+ inline GLenum getRenderTarget() {
+ return renderTarget;
+ }
+
+ inline void setRenderTarget(GLenum renderTarget) {
+ this->renderTarget = renderTarget;
+ }
+
+ void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) {
+ if (firstWrap || force || wrapS != texture.wrapS || wrapT != texture.wrapT) {
+ firstWrap = true;
+ texture.setWrap(wrapS, wrapT);
+ if (bindTexture) {
+ glBindTexture(renderTarget, texture.id);
+ }
+ glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
+ glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
+ }
+ }
+
+ void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) {
+ if (firstFilter || force || min != texture.minFilter || mag != texture.magFilter) {
+ firstFilter = false;
+ texture.setFilter(min, mag);
+ if (bindTexture) {
+ glBindTexture(renderTarget, texture.id);
+ }
+ glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
+ glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
+ }
+ }
+
+ inline bool isCacheable() {
+ return cacheable;
+ }
+
+ inline void setCacheable(bool cacheable) {
+ this->cacheable = cacheable;
+ }
+
+ inline bool isTextureLayer() {
+ return textureLayer;
+ }
+
+ inline void setTextureLayer(bool textureLayer) {
+ this->textureLayer = textureLayer;
+ }
+
+ inline SkiaColorFilter* getColorFilter() {
+ return colorFilter;
+ }
+
+ inline void setColorFilter(SkiaColorFilter* filter) {
+ colorFilter = filter;
+ }
+
+ inline void bindTexture() {
+ glBindTexture(renderTarget, texture.id);
+ }
+
+ inline void generateTexture() {
+ glGenTextures(1, &texture.id);
+ }
+
+ inline void deleteTexture() {
+ if (texture.id) glDeleteTextures(1, &texture.id);
+ }
+
+ inline void allocateTexture(GLenum format, GLenum storage) {
+ glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL);
+ }
+
+ inline mat4& getTexTransform() {
+ return texTransform;
}
/**
@@ -82,43 +227,6 @@
Rect texCoords;
/**
- * Name of the FBO used to render the layer. If the name is 0
- * this layer is not backed by an FBO, but a simple texture.
- */
- GLuint fbo;
-
- /**
- * Opacity of the layer.
- */
- int alpha;
- /**
- * Blending mode of the layer.
- */
- SkXfermode::Mode mode;
- /**
- * Indicates whether this layer should be blended.
- */
- bool blend;
-
- /**
- * Indicates whether this layer has been used already.
- */
- bool empty;
-
- /**
- * Name of the texture used to render the layer.
- */
- GLuint texture;
- /**
- * Width of the layer texture.
- */
- uint32_t width;
- /**
- * Height of the layer texture.
- */
- uint32_t height;
-
- /**
* Dirty region indicating what parts of the layer
* have been drawn.
*/
@@ -130,37 +238,66 @@
Rect regionRect;
/**
- * Color filter used to draw this layer. Optional.
- */
- SkiaColorFilter* colorFilter;
-
- /**
* If the layer can be rendered as a mesh, this is non-null.
*/
TextureVertex* mesh;
uint16_t* meshIndices;
GLsizei meshElementCount;
+private:
+ /**
+ * Name of the FBO used to render the layer. If the name is 0
+ * this layer is not backed by an FBO, but a simple texture.
+ */
+ GLuint fbo;
+
+ /**
+ * Indicates whether this layer has been used already.
+ */
+ bool empty;
+
+ /**
+ * The texture backing this layer.
+ */
+ Texture texture;
+
/**
* If set to true (by default), the layer can be reused.
*/
- bool isCacheable;
+ bool cacheable;
/**
* When set to true, this layer must be treated as a texture
* layer.
*/
- bool isTextureLayer;
+ bool textureLayer;
+
+ /**
+ * Indicates the render target.
+ */
+ GLenum renderTarget;
+
+ /**
+ * Color filter used to draw this layer. Optional.
+ */
+ SkiaColorFilter* colorFilter;
+
+ /**
+ * Opacity of the layer.
+ */
+ int alpha;
+ /**
+ * Blending mode of the layer.
+ */
+ SkXfermode::Mode mode;
/**
* Optional texture coordinates transform.
*/
mat4 texTransform;
- /**
- * Indicates the render target.
- */
- GLenum renderTarget;
+ bool firstFilter;
+ bool firstWrap;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index b2d795f..1a15e87 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -68,8 +68,8 @@
void LayerCache::deleteLayer(Layer* layer) {
if (layer) {
- mSize -= layer->width * layer->height * 4;
- glDeleteTextures(1, &layer->texture);
+ mSize -= layer->getWidth() * layer->getHeight() * 4;
+ layer->deleteTexture();
delete layer;
}
}
@@ -93,29 +93,23 @@
mCache.removeAt(index);
layer = entry.mLayer;
- mSize -= layer->width * layer->height * 4;
+ mSize -= layer->getWidth() * layer->getHeight() * 4;
- LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
+ LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
} else {
LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
layer = new Layer(entry.mWidth, entry.mHeight);
- layer->blend = true;
- layer->empty = true;
- layer->fbo = 0;
- layer->colorFilter = NULL;
+ layer->setBlend(true);
+ layer->setEmpty(true);
+ layer->setFbo(0);
- glGenTextures(1, &layer->texture);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
-
+ layer->generateTexture();
+ layer->bindTexture();
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
#if DEBUG_LAYERS
size_t size = mCache.size();
for (size_t i = 0; i < size; i++) {
@@ -133,30 +127,30 @@
// size already in the cache, and reuse it instead of creating a new one
LayerEntry entry(width, height);
- if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) {
+ if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) {
return true;
}
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ uint32_t oldWidth = layer->getWidth();
+ uint32_t oldHeight = layer->getHeight();
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glActiveTexture(GL_TEXTURE0);
+ layer->bindTexture();
+ layer->setSize(entry.mWidth, entry.mHeight);
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
if (glGetError() != GL_NO_ERROR) {
+ layer->setSize(oldWidth, oldHeight);
return false;
}
- layer->width = entry.mWidth;
- layer->height = entry.mHeight;
-
return true;
}
bool LayerCache::put(Layer* layer) {
- if (!layer->isCacheable) return false;
+ if (!layer->isCacheable()) return false;
- const uint32_t size = layer->width * layer->height * 4;
+ const uint32_t size = layer->getWidth() * layer->getHeight() * 4;
// Don't even try to cache a layer that's bigger than the cache
if (size < mMaxSize) {
// TODO: Use an LRU
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index d2d5f39..81b8bf3 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -119,7 +119,7 @@
}
LayerEntry(Layer* layer):
- mLayer(layer), mWidth(layer->width), mHeight(layer->height) {
+ mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) {
}
bool operator<(const LayerEntry& rhs) const {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e034a868..1fa343b 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -32,9 +32,9 @@
///////////////////////////////////////////////////////////////////////////////
void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
- LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
+ LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
- glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
const float width = mLayer->layer.getWidth();
const float height = mLayer->layer.getHeight();
@@ -62,14 +62,14 @@
generateMesh();
- LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->fbo);
+ LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo());
// No need to unbind our FBO, this will be taken care of by the caller
// who will invoke OpenGLRenderer::resume()
}
GLint LayerRenderer::getTargetFbo() {
- return mLayer->fbo;
+ return mLayer->getFbo();
}
///////////////////////////////////////////////////////////////////////////////
@@ -128,8 +128,8 @@
}
mLayer->meshElementCount = elementCount;
- const float texX = 1.0f / float(mLayer->width);
- const float texY = 1.0f / float(mLayer->height);
+ const float texX = 1.0f / float(mLayer->getWidth());
+ const float texY = 1.0f / float(mLayer->getHeight());
const float height = mLayer->layer.getHeight();
TextureVertex* mesh = mLayer->mesh;
@@ -182,40 +182,41 @@
return NULL;
}
- layer->fbo = fbo;
+ layer->setFbo(fbo);
layer->layer.set(0.0f, 0.0f, width, height);
- layer->texCoords.set(0.0f, height / float(layer->height),
- width / float(layer->width), 0.0f);
- layer->alpha = 255;
- layer->mode = SkXfermode::kSrcOver_Mode;
- layer->blend = !isOpaque;
- layer->colorFilter = NULL;
+ layer->texCoords.set(0.0f, height / float(layer->getHeight()),
+ width / float(layer->getWidth()), 0.0f);
+ layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
+ layer->setBlend(!isOpaque);
+ layer->setColorFilter(NULL);
layer->region.clear();
GLuint previousFbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+ layer->bindTexture();
// Initialize the texture if needed
- if (layer->empty) {
- layer->empty = false;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ if (layer->isEmpty()) {
+ layer->setEmpty(false);
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
if (glGetError() != GL_NO_ERROR) {
LOGD("Could not allocate texture");
+
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
Caches::getInstance().fboCache.put(fbo);
+
+ layer->deleteTexture();
delete layer;
+
return NULL;
}
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
+ layer->getTexture(), 0);
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -229,14 +230,14 @@
bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
if (layer) {
- LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->fbo, width, height);
+ LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height);
if (Caches::getInstance().layerCache.resize(layer, width, height)) {
layer->layer.set(0.0f, 0.0f, width, height);
- layer->texCoords.set(0.0f, height / float(layer->height),
- width / float(layer->width), 0.0f);
+ layer->texCoords.set(0.0f, height / float(layer->getHeight()),
+ width / float(layer->getWidth()), 0.0f);
} else {
- if (layer->texture) glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
return false;
}
@@ -245,37 +246,23 @@
return true;
}
-static void setTextureParameters(Layer* layer) {
- glBindTexture(layer->renderTarget, layer->texture);
-
- glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-}
-
Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
LAYER_RENDERER_LOGD("Creating new texture layer");
Layer* layer = new Layer(0, 0);
- layer->isCacheable = false;
- layer->isTextureLayer = true;
- layer->blend = !isOpaque;
- layer->empty = true;
- layer->fbo = 0;
- layer->colorFilter = NULL;
- layer->fbo = 0;
+ layer->setCacheable(false);
+ layer->setTextureLayer(true);
+ layer->setBlend(!isOpaque);
+ layer->setEmpty(true);
+ layer->setFbo(0);
+ layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
- layer->alpha = 255;
- layer->mode = SkXfermode::kSrcOver_Mode;
- layer->colorFilter = NULL;
layer->region.clear();
- layer->renderTarget = GL_NONE; // see ::updateTextureLayer()
+ layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
glActiveTexture(GL_TEXTURE0);
- glGenTextures(1, &layer->texture);
+ layer->generateTexture();
return layer;
}
@@ -283,31 +270,32 @@
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, GLenum renderTarget, float* transform) {
if (layer) {
- layer->blend = !isOpaque;
- layer->width = width;
- layer->height = height;
+ layer->setBlend(!isOpaque);
+ layer->setSize(width, height);
layer->layer.set(0.0f, 0.0f, width, height);
layer->region.set(width, height);
layer->regionRect.set(0.0f, 0.0f, width, height);
- layer->texTransform.load(transform);
+ layer->getTexTransform().load(transform);
- if (renderTarget != layer->renderTarget) {
- layer->renderTarget = renderTarget;
- setTextureParameters(layer);
+ if (renderTarget != layer->getRenderTarget()) {
+ layer->setRenderTarget(renderTarget);
+ layer->bindTexture();
+ layer->setFilter(GL_NEAREST, GL_NEAREST, false, true);
+ layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false, true);
}
}
}
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
- LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo);
+ LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->getFbo());
- if (layer->fbo) {
- Caches::getInstance().fboCache.put(layer->fbo);
+ if (layer->getFbo()) {
+ Caches::getInstance().fboCache.put(layer->getFbo());
}
if (!Caches::getInstance().layerCache.put(layer)) {
- if (layer->texture) glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
} else {
layer->region.clear();
@@ -317,7 +305,7 @@
void LayerRenderer::destroyLayerDeferred(Layer* layer) {
if (layer) {
- LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->fbo);
+ LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
Caches::getInstance().deleteLayerDeferred(layer);
}
@@ -325,7 +313,7 @@
bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
- if (layer && layer->isTextureLayer && bitmap->width() <= caches.maxTextureSize &&
+ if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
bitmap->height() <= caches.maxTextureSize) {
GLuint fbo = caches.fboCache.get();
@@ -365,12 +353,11 @@
break;
}
- float alpha = layer->alpha;
- SkXfermode::Mode mode = layer->mode;
+ float alpha = layer->getAlpha();
+ SkXfermode::Mode mode = layer->getMode();
- layer->mode = SkXfermode::kSrc_Mode;
- layer->alpha = 255;
- layer->fbo = fbo;
+ layer->setAlpha(255, SkXfermode::kSrc_Mode);
+ layer->setFbo(fbo);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -381,8 +368,8 @@
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -399,7 +386,7 @@
LayerRenderer renderer(layer);
renderer.setViewport(bitmap->width(), bitmap->height());
renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
- bitmap->width(), bitmap->height(), !layer->blend);
+ bitmap->width(), bitmap->height(), !layer->isBlend());
if ((error = glGetError()) != GL_NO_ERROR) goto error;
{
@@ -424,9 +411,8 @@
#endif
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- layer->mode = mode;
- layer->alpha = alpha;
- layer->fbo = 0;
+ layer->setAlpha(alpha, mode);
+ layer->setFbo(0);
glDeleteTextures(1, &texture);
caches.fboCache.put(fbo);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1c06a0b..a349121 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -449,12 +449,11 @@
return false;
}
- layer->mode = mode;
- layer->alpha = alpha;
+ layer->setAlpha(alpha, mode);
layer->layer.set(bounds);
- layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height),
- bounds.getWidth() / float(layer->width), 0.0f);
- layer->colorFilter = mColorFilter;
+ layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
+ bounds.getWidth() / float(layer->getWidth()), 0.0f);
+ layer->setColorFilter(mColorFilter);
// Save the layer in the snapshot
snapshot->flags |= Snapshot::kFlagIsLayer;
@@ -464,12 +463,13 @@
return createFboLayer(layer, bounds, snapshot, previousFbo);
} else {
// Copy the framebuffer into the layer
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ layer->bindTexture();
if (!bounds.isEmpty()) {
- if (layer->empty) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
- snapshot->height - bounds.bottom, layer->width, layer->height, 0);
- layer->empty = false;
+ if (layer->isEmpty()) {
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ bounds.left, snapshot->height - bounds.bottom,
+ layer->getWidth(), layer->getHeight(), 0);
+ layer->setEmpty(false);
} else {
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
@@ -485,7 +485,7 @@
bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
GLuint previousFbo) {
- layer->fbo = mCaches.fboCache.get();
+ layer->setFbo(mCaches.fboCache.get());
#if RENDER_LAYERS_AS_REGIONS
snapshot->region = &snapshot->layer->region;
@@ -507,7 +507,7 @@
clip.translate(-bounds.left, -bounds.top);
snapshot->flags |= Snapshot::kFlagIsFboLayer;
- snapshot->fbo = layer->fbo;
+ snapshot->fbo = layer->getFbo();
snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
@@ -516,18 +516,17 @@
snapshot->orthoMatrix.load(mOrthoMatrix);
// Bind texture to FBO
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+ layer->bindTexture();
// Initialize the texture if needed
- if (layer->empty) {
- layer->empty = false;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ if (layer->isEmpty()) {
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
+ layer->setEmpty(false);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
+ layer->getTexture(), 0);
#if DEBUG_LAYERS_AS_REGIONS
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -535,8 +534,8 @@
LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
- mCaches.fboCache.put(layer->fbo);
+ layer->deleteTexture();
+ mCaches.fboCache.put(layer->getFbo());
delete layer;
@@ -578,11 +577,11 @@
Layer* layer = current->layer;
const Rect& rect = layer->layer;
- if (!fboLayer && layer->alpha < 255) {
+ if (!fboLayer && layer->getAlpha() < 255) {
drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
- layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
+ layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
// Required below, composeLayerRect() will divide by 255
- layer->alpha = 255;
+ layer->setAlpha(255);
}
mCaches.unbindMeshBuffer();
@@ -593,18 +592,16 @@
// drawing only the dirty region
if (fboLayer) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
- if (layer->colorFilter) {
- setupColorFilter(layer->colorFilter);
+ if (layer->getColorFilter()) {
+ setupColorFilter(layer->getColorFilter());
}
composeLayerRegion(layer, rect);
- if (layer->colorFilter) {
+ if (layer->getColorFilter()) {
resetColorFilter();
}
- } else {
- if (!rect.isEmpty()) {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
- composeLayerRect(layer, rect, true);
- }
+ } else if (!rect.isEmpty()) {
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+ composeLayerRect(layer, rect, true);
}
if (fboLayer) {
@@ -622,16 +619,16 @@
// Failing to add the layer to the cache should happen only if the layer is too large
if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
- glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
}
}
void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
- float alpha = layer->alpha / 255.0f;
+ float alpha = layer->getAlpha() / 255.0f;
setupDraw();
- if (layer->renderTarget == GL_TEXTURE_2D) {
+ if (layer->getRenderTarget() == GL_TEXTURE_2D) {
setupDrawWithTexture();
} else {
setupDrawWithExternalTexture();
@@ -639,17 +636,28 @@
setupDrawTextureTransform();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode);
+ setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
setupDrawProgram();
- setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- if (layer->renderTarget == GL_TEXTURE_2D) {
- setupDrawTexture(layer->texture);
+ if (layer->getRenderTarget() == GL_TEXTURE_2D) {
+ setupDrawTexture(layer->getTexture());
} else {
- setupDrawExternalTexture(layer->texture);
+ setupDrawExternalTexture(layer->getTexture());
}
- setupDrawTextureTransformUniforms(layer->texTransform);
+ if (mSnapshot->transform->isPureTranslate() &&
+ layer->getWidth() == (uint32_t) rect.getWidth() &&
+ layer->getHeight() == (uint32_t) rect.getHeight()) {
+ const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+ }
+ setupDrawTextureTransformUniforms(layer->getTexTransform());
setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -658,14 +666,34 @@
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- if (!layer->isTextureLayer) {
+ if (!layer->isTextureLayer()) {
const Rect& texCoords = layer->texCoords;
resetDrawTextureTexCoords(texCoords.left, texCoords.top,
texCoords.right, texCoords.bottom);
- drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
- layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
- &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+ float x = rect.left;
+ float y = rect.top;
+ bool simpleTransform = mSnapshot->transform->isPureTranslate() &&
+ layer->getWidth() == (uint32_t) rect.getWidth() &&
+ layer->getHeight() == (uint32_t) rect.getHeight();
+
+ if (simpleTransform) {
+ // When we're swapping, the layer is already in screen coordinates
+ if (!swap) {
+ x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+ }
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST, true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR, true);
+ }
+
+ drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
+ layer->getTexture(), layer->getAlpha() / 255.0f,
+ layer->getMode(), layer->isBlend(),
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
+ GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
} else {
@@ -690,9 +718,9 @@
size_t count;
const android::Rect* rects = layer->region.getArray(&count);
- const float alpha = layer->alpha / 255.0f;
- const float texX = 1.0f / float(layer->width);
- const float texY = 1.0f / float(layer->height);
+ const float alpha = layer->getAlpha() / 255.0f;
+ const float texX = 1.0f / float(layer->getWidth());
+ const float texY = 1.0f / float(layer->getHeight());
const float height = rect.getHeight();
TextureVertex* mesh = mCaches.getRegionMesh();
@@ -702,13 +730,22 @@
setupDrawWithTexture();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
+ setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawTexture(layer->texture);
- setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+ setupDrawTexture(layer->getTexture());
+ if (mSnapshot->transform->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+ }
setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
for (size_t i = 0; i < count; i++) {
@@ -2154,8 +2191,7 @@
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- layer->alpha = alpha;
- layer->mode = mode;
+ layer->setAlpha(alpha, mode);
#if RENDER_LAYERS_AS_REGIONS
if (!layer->region.isEmpty()) {
@@ -2169,13 +2205,23 @@
setupDrawWithTexture();
setupDrawColor(a, a, a, a);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
+ setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
setupDrawProgram();
- setupDrawModelViewTranslate(x, y,
- x + layer->layer.getWidth(), y + layer->layer.getHeight());
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawTexture(layer->texture);
+ setupDrawTexture(layer->getTexture());
+ if (mSnapshot->transform->isPureTranslate()) {
+ x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
+ y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelViewTranslate(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelViewTranslate(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight());
+ }
setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
glDrawElements(GL_TRIANGLES, layer->meshElementCount,
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index b048469..f4d9686 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -537,7 +537,7 @@
const float pathWidth = fmax(bounds.width(), 1.0f);
const float pathHeight = fmax(bounds.height(), 1.0f);
- const float offset = fmax(paint->getStrokeWidth(), 1.0f) * 1.5f;
+ const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 4922bb3..c6ae326 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -29,8 +29,22 @@
Texture() {
cleanup = false;
bitmapSize = 0;
+
wrapS = GL_CLAMP_TO_EDGE;
wrapT = GL_CLAMP_TO_EDGE;
+
+ minFilter = GL_NEAREST;
+ magFilter = GL_NEAREST;
+ }
+
+ void setWrap(GLenum wrapS, GLenum wrapT) {
+ this->wrapS = wrapS;
+ this->wrapT = wrapT;
+ }
+
+ void setFilter(GLenum min, GLenum mag) {
+ minFilter = min;
+ magFilter = mag;
}
/**
@@ -67,6 +81,12 @@
*/
GLenum wrapS;
GLenum wrapT;
+
+ /**
+ * Last filters set on this texture. Defaults to GL_NEAREST.
+ */
+ GLenum minFilter;
+ GLenum magFilter;
}; // struct Texture
class AutoTexture {
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 8120864..62eb24e 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -66,65 +66,6 @@
}
-// Input: cacheDir
-// Input: resName
-// Input: extName
-//
-// Note: cacheFile = resName + extName
-//
-// Output: Returns cachePath == cacheDir + cacheFile
-static char *genCacheFileName(const char *cacheDir,
- const char *resName,
- const char *extName) {
- char cachePath[512];
- char cacheFile[sizeof(cachePath)];
- const size_t kBufLen = sizeof(cachePath) - 1;
-
- cacheFile[0] = '\0';
- // Note: resName today is usually something like
- // "/com.android.fountain:raw/fountain"
- if (resName[0] != '/') {
- // Get the absolute path of the raw/***.bc file.
-
- // Generate the absolute path. This doesn't do everything it
- // should, e.g. if resName is "./out/whatever" it doesn't crunch
- // the leading "./" out because this if-block is not triggered,
- // but it'll make do.
- //
- if (getcwd(cacheFile, kBufLen) == NULL) {
- LOGE("Can't get CWD while opening raw/***.bc file\n");
- return NULL;
- }
- // Append "/" at the end of cacheFile so far.
- strncat(cacheFile, "/", kBufLen);
- }
-
- // cacheFile = resName + extName
- //
- strncat(cacheFile, resName, kBufLen);
- if (extName != NULL) {
- // TODO(srhines): strncat() is a bit dangerous
- strncat(cacheFile, extName, kBufLen);
- }
-
- // Turn the path into a flat filename by replacing
- // any slashes after the first one with '@' characters.
- char *cp = cacheFile + 1;
- while (*cp != '\0') {
- if (*cp == '/') {
- *cp = '@';
- }
- cp++;
- }
-
- // Tack on the file name for the actual cache file path.
- strncpy(cachePath, cacheDir, kBufLen);
- strncat(cachePath, cacheFile, kBufLen);
-
- LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
- return strdup(cachePath);
-}
-
bool rsdScriptInit(const Context *rsc,
ScriptC *script,
char const *resName,
@@ -164,15 +105,12 @@
goto error;
}
-#if 1
if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) {
LOGE("bcc: FAILS to link bitcode");
goto error;
}
-#endif
- cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
- if (bccPrepareExecutable(drv->mBccScript, cachePath, 0) != 0) {
+ if (bccPrepareExecutableEx(drv->mBccScript, cacheDir, resName, 0) != 0) {
LOGE("bcc: FAILS to prepare executable");
goto error;
}
@@ -214,14 +152,13 @@
const char ** mPragmaKeys;
const char ** mPragmaValues;
- const static int pragmaMax = 16;
drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript);
if (drv->mPragmaCount <= 0) {
drv->mPragmaKeys = NULL;
drv->mPragmaValues = NULL;
} else {
- drv->mPragmaKeys = (const char **) calloc(drv->mFieldCount, sizeof(const char *));
- drv->mPragmaValues = (const char **) calloc(drv->mFieldCount, sizeof(const char *));
+ drv->mPragmaKeys = (const char **) calloc(drv->mPragmaCount, sizeof(const char *));
+ drv->mPragmaValues = (const char **) calloc(drv->mPragmaCount, sizeof(const char *));
bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues);
}
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 1f7bb0f..04446ad 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -99,9 +99,8 @@
for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
EGLint value = -1;
- EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
- EGLint error = eglGetError();
- if (returnVal && error == EGL_SUCCESS) {
+ EGLBoolean returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ if (returnVal) {
LOGV(" %s: %d (0x%x)", names[j].name, value, value);
}
}
@@ -169,6 +168,24 @@
configAttribsPtr[1] = EGL_OPENGL_ES2_BIT;
configAttribsPtr += 2;
+ configAttribsPtr[0] = EGL_RED_SIZE;
+ configAttribsPtr[1] = 8;
+ configAttribsPtr += 2;
+
+ configAttribsPtr[0] = EGL_GREEN_SIZE;
+ configAttribsPtr[1] = 8;
+ configAttribsPtr += 2;
+
+ configAttribsPtr[0] = EGL_BLUE_SIZE;
+ configAttribsPtr[1] = 8;
+ configAttribsPtr += 2;
+
+ if (rsc->mUserSurfaceConfig.alphaMin > 0) {
+ configAttribsPtr[0] = EGL_ALPHA_SIZE;
+ configAttribsPtr[1] = rsc->mUserSurfaceConfig.alphaMin;
+ configAttribsPtr += 2;
+ }
+
if (rsc->mUserSurfaceConfig.depthMin > 0) {
configAttribsPtr[0] = EGL_DEPTH_SIZE;
configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin;
@@ -191,16 +208,53 @@
eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
checkEglError("eglInitialize");
- PixelFormat pf = PIXEL_FORMAT_RGBA_8888;
- if (rsc->mUserSurfaceConfig.alphaMin == 0) {
- pf = PIXEL_FORMAT_RGBX_8888;
+ EGLBoolean ret;
+
+ EGLint numConfigs = -1, n = 0;
+ ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
+ checkEglError("eglGetConfigs", ret);
+
+ if (numConfigs) {
+ EGLConfig* const configs = new EGLConfig[numConfigs];
+
+ ret = eglChooseConfig(dc->gl.egl.display,
+ configAttribs, configs, numConfigs, &n);
+ if (!ret || !n) {
+ checkEglError("eglChooseConfig", ret);
+ LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
+ }
+
+ // The first config is guaranteed to over-satisfy the constraints
+ dc->gl.egl.config = configs[0];
+
+ // go through the list and skip configs that over-satisfy our needs
+ for (int i=0 ; i<n ; i++) {
+ if (rsc->mUserSurfaceConfig.alphaMin <= 0) {
+ EGLint alphaSize;
+ eglGetConfigAttrib(dc->gl.egl.display,
+ configs[i], EGL_ALPHA_SIZE, &alphaSize);
+ if (alphaSize > 0) {
+ continue;
+ }
+ }
+
+ if (rsc->mUserSurfaceConfig.depthMin <= 0) {
+ EGLint depthSize;
+ eglGetConfigAttrib(dc->gl.egl.display,
+ configs[i], EGL_DEPTH_SIZE, &depthSize);
+ if (depthSize > 0) {
+ continue;
+ }
+ }
+
+ // Found one!
+ dc->gl.egl.config = configs[i];
+ break;
+ }
+
+ delete [] configs;
}
- status_t err = EGLUtils::selectConfigForPixelFormat(dc->gl.egl.display, configAttribs,
- pf, &dc->gl.egl.config);
- if (err) {
- LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
- }
//if (props.mLogVisual) {
if (0) {
printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config);
@@ -227,8 +281,8 @@
return false;
}
- EGLBoolean ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
- dc->gl.egl.surfaceDefault, dc->gl.egl.context);
+ ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
+ dc->gl.egl.surfaceDefault, dc->gl.egl.context);
if (ret == EGL_FALSE) {
LOGE("eglMakeCurrent returned EGL_FALSE");
checkEglError("eglMakeCurrent", ret);
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
index f24a71d..020646b 100644
--- a/libs/ui/EGLUtils.cpp
+++ b/libs/ui/EGLUtils.cpp
@@ -24,6 +24,8 @@
#include <EGL/egl.h>
+#include <system/graphics.h>
+
#include <private/ui/android_natives_priv.h>
// ----------------------------------------------------------------------------
@@ -67,31 +69,49 @@
return BAD_VALUE;
// Get all the "potential match" configs...
- if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+ if (eglChooseConfig(dpy, attrs, 0, 0, &numConfigs) == EGL_FALSE)
return BAD_VALUE;
- EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
- if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
- free(configs);
- return BAD_VALUE;
- }
-
- int i;
- EGLConfig config = NULL;
- for (i=0 ; i<n ; i++) {
- EGLint nativeVisualId = 0;
- eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
- if (nativeVisualId>0 && format == nativeVisualId) {
+ if (numConfigs) {
+ EGLConfig* const configs = new EGLConfig[numConfigs];
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ delete [] configs;
+ return BAD_VALUE;
+ }
+
+ bool hasAlpha = false;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ hasAlpha = true;
+ break;
+ }
+
+ // The first config is guaranteed to over-satisfy the constraints
+ EGLConfig config = configs[0];
+
+ // go through the list and skip configs that over-satisfy our needs
+ int i;
+ for (i=0 ; i<n ; i++) {
+ if (!hasAlpha) {
+ EGLint alphaSize;
+ eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &alphaSize);
+ if (alphaSize > 0) {
+ continue;
+ }
+ }
config = configs[i];
break;
}
- }
- free(configs);
-
- if (i<n) {
- *outConfig = config;
- return NO_ERROR;
+ delete [] configs;
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
+ }
}
return NAME_NOT_FOUND;
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 6df2f73..816d215 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -104,10 +104,9 @@
public static final int FILE_TYPE_MS_POWERPOINT = 106;
public static final int FILE_TYPE_ZIP = 107;
- static class MediaFileType {
-
- int fileType;
- String mimeType;
+ public static class MediaFileType {
+ public final int fileType;
+ public final String mimeType;
MediaFileType(int fileType, String mimeType) {
this.fileType = fileType;
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index c55338a..18742ea 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -368,6 +368,34 @@
}
}
+ private class FileInserter {
+
+ ContentValues[] mValues = new ContentValues[1000];
+ int mIndex = 0;
+
+ public Uri insert(ContentValues values) {
+ if (mIndex == mValues.length) {
+ flush();
+ }
+ mValues[mIndex++] = values;
+ // URI not needed when doing bulk inserts
+ return null;
+ }
+
+ public void flush() {
+ while (mIndex < mValues.length) {
+ mValues[mIndex++] = null;
+ }
+ try {
+ mMediaProvider.bulkInsert(mFilesUri, mValues);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in FileInserter.flush()", e);
+ }
+ mIndex = 0;
+ }
+ }
+ private FileInserter mFileInserter;
+
// hashes file path to FileCacheEntry.
// path should be lower case if mCaseInsensitivePaths is true
private HashMap<String, FileCacheEntry> mFileCache;
@@ -805,37 +833,31 @@
}
}
- Uri tableUri = mFilesUri;
- if (!mNoMedia) {
- if (MediaFile.isVideoFileType(mFileType)) {
- tableUri = mVideoUri;
- } else if (MediaFile.isImageFileType(mFileType)) {
- tableUri = mImagesUri;
- } else if (MediaFile.isAudioFileType(mFileType)) {
- tableUri = mAudioUri;
- }
- }
Uri result = null;
if (rowId == 0) {
if (mMtpObjectHandle != 0) {
values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
}
- if (tableUri == mFilesUri) {
- int format = entry.mFormat;
- if (format == 0) {
- format = MediaFile.getFormatCode(entry.mPath, mMimeType);
- }
- values.put(Files.FileColumns.FORMAT, format);
+ int format = entry.mFormat;
+ if (format == 0) {
+ format = MediaFile.getFormatCode(entry.mPath, mMimeType);
}
+ values.put(Files.FileColumns.FORMAT, format);
+
// new file, insert it
- result = mMediaProvider.insert(tableUri, values);
+ if (mFileInserter != null) {
+ result = mFileInserter.insert(values);
+ } else {
+ result = mMediaProvider.insert(mFilesUri, values);
+ }
+
if (result != null) {
rowId = ContentUris.parseId(result);
entry.mRowId = rowId;
}
} else {
// updated file
- result = ContentUris.withAppendedId(tableUri, rowId);
+ result = ContentUris.withAppendedId(mFilesUri, rowId);
// path should never change, and we want to avoid replacing mixed cased paths
// with squashed lower case paths
values.remove(MediaStore.MediaColumns.DATA);
@@ -854,7 +876,7 @@
new String[] { genre }, null);
if (cursor == null || cursor.getCount() == 0) {
// genre does not exist, so create the genre in the genre table
- values.clear();
+ values = new ContentValues();
values.put(MediaStore.Audio.Genres.NAME, genre);
uri = mMediaProvider.insert(mGenresUri, values);
} else {
@@ -876,7 +898,7 @@
if (uri != null) {
// add entry to audio_genre_map
- values.clear();
+ values = new ContentValues();
values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId));
mMediaProvider.insert(uri, values);
}
@@ -885,19 +907,19 @@
if (notifications && !mDefaultNotificationSet) {
if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
- setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
+ setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, mFilesUri, rowId);
mDefaultNotificationSet = true;
}
} else if (ringtones && !mDefaultRingtoneSet) {
if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
- setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
+ setSettingIfNotSet(Settings.System.RINGTONE, mFilesUri, rowId);
mDefaultRingtoneSet = true;
}
} else if (alarms && !mDefaultAlarmSet) {
if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
- setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
+ setSettingIfNotSet(Settings.System.ALARM_ALERT, mFilesUri, rowId);
mDefaultAlarmSet = true;
}
}
@@ -1165,10 +1187,14 @@
initialize(volumeName);
prescan(null, true);
long prescan = System.currentTimeMillis();
+ mFileInserter = new FileInserter();
for (int i = 0; i < directories.length; i++) {
processDirectory(directories[i], mClient);
}
+ mFileInserter.flush();
+ mFileInserter = null;
+
long scan = System.currentTimeMillis();
postscan(directories);
long end = System.currentTimeMillis();
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index b75b11a..76c8569 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -330,7 +330,6 @@
}
int count = (c == null ? 1 : c.getCount());
- Log.d(TAG, "count: " + count);
MtpPropertyList result = new MtpPropertyList(count * mProperties.length,
MtpConstants.RESPONSE_OK);
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 7932d34..da190a6 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -32,6 +32,7 @@
private final String mDescription;
private final long mReserveSpace;
private final boolean mRemovable;
+ private final long mMaxFileSize;
public MtpStorage(StorageVolume volume) {
mStorageId = volume.getStorageId();
@@ -39,6 +40,7 @@
mDescription = volume.getDescription();
mReserveSpace = volume.getMtpReserveSpace();
mRemovable = volume.isRemovable();
+ mMaxFileSize = volume.getMaxFileSize();
}
/**
@@ -98,4 +100,13 @@
public final boolean isRemovable() {
return mRemovable;
}
+
+ /**
+ * Returns maximum file size for the storage, or zero if it is unbounded.
+ *
+ * @return maximum file size
+ */
+ public long getMaxFileSize() {
+ return mMaxFileSize;
+ }
}
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index aaf85c3..446b630 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -48,6 +48,7 @@
static jfieldID field_MtpStorage_description;
static jfieldID field_MtpStorage_reserveSpace;
static jfieldID field_MtpStorage_removable;
+static jfieldID field_MtpStorage_maxFileSize;
static Mutex sMutex;
@@ -228,12 +229,14 @@
jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
jlong reserveSpace = env->GetLongField(jstorage, field_MtpStorage_reserveSpace);
jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable);
+ jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize);
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr != NULL) {
const char *descriptionStr = env->GetStringUTFChars(description, NULL);
if (descriptionStr != NULL) {
- MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, reserveSpace, removable);
+ MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
+ reserveSpace, removable, maxFileSize);
thread->addStorage(storage);
env->ReleaseStringUTFChars(path, pathStr);
env->ReleaseStringUTFChars(description, descriptionStr);
@@ -312,6 +315,11 @@
LOGE("Can't find MtpStorage.mRemovable");
return -1;
}
+ field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J");
+ if (field_MtpStorage_maxFileSize == NULL) {
+ LOGE("Can't find MtpStorage.mMaxFileSize");
+ return -1;
+ }
clazz_MtpStorage = (jclass)env->NewGlobalRef(clazz);
clazz = env->FindClass("android/mtp/MtpServer");
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index b003476..223e0be 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1136,10 +1136,69 @@
clipVideoFrameRate();
clipVideoFrameWidth();
clipVideoFrameHeight();
+ setDefaultProfileIfNecessary();
}
return OK;
}
+// Set to use AVC baseline profile if the encoding parameters matches
+// CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service.
+void StagefrightRecorder::setDefaultProfileIfNecessary() {
+ LOGV("setDefaultProfileIfNecessary");
+
+ camcorder_quality quality = CAMCORDER_QUALITY_LOW;
+
+ int64_t durationUs = mEncoderProfiles->getCamcorderProfileParamByName(
+ "duration", mCameraId, quality) * 1000000LL;
+
+ int fileFormat = mEncoderProfiles->getCamcorderProfileParamByName(
+ "file.format", mCameraId, quality);
+
+ int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName(
+ "vid.codec", mCameraId, quality);
+
+ int videoBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
+ "vid.bps", mCameraId, quality);
+
+ int videoFrameRate = mEncoderProfiles->getCamcorderProfileParamByName(
+ "vid.fps", mCameraId, quality);
+
+ int videoFrameWidth = mEncoderProfiles->getCamcorderProfileParamByName(
+ "vid.width", mCameraId, quality);
+
+ int videoFrameHeight = mEncoderProfiles->getCamcorderProfileParamByName(
+ "vid.height", mCameraId, quality);
+
+ int audioCodec = mEncoderProfiles->getCamcorderProfileParamByName(
+ "aud.codec", mCameraId, quality);
+
+ int audioBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
+ "aud.bps", mCameraId, quality);
+
+ int audioSampleRate = mEncoderProfiles->getCamcorderProfileParamByName(
+ "aud.hz", mCameraId, quality);
+
+ int audioChannels = mEncoderProfiles->getCamcorderProfileParamByName(
+ "aud.ch", mCameraId, quality);
+
+ if (durationUs == mMaxFileDurationUs &&
+ fileFormat == mOutputFormat &&
+ videoCodec == mVideoEncoder &&
+ videoBitRate == mVideoBitRate &&
+ videoFrameRate == mFrameRate &&
+ videoFrameWidth == mVideoWidth &&
+ videoFrameHeight == mVideoHeight &&
+ audioCodec == mAudioEncoder &&
+ audioBitRate == mAudioBitRate &&
+ audioSampleRate == mSampleRate &&
+ audioChannels == mAudioChannels) {
+ if (videoCodec == VIDEO_ENCODER_H264) {
+ LOGI("Force to use AVC baseline profile");
+ setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline);
+ }
+ }
+}
+
status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
clipAudioBitRate();
clipAudioSampleRate();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index cb9c406..034b373 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -174,6 +174,7 @@
void clipAudioBitRate();
void clipAudioSampleRate();
void clipNumberOfAudioChannels();
+ void setDefaultProfileIfNecessary();
StagefrightRecorder(const StagefrightRecorder &);
StagefrightRecorder &operator=(const StagefrightRecorder &);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 1ac2c1f..06363ee 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1295,13 +1295,6 @@
h264type.nAllowedPictureTypes =
OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
- h264type.nSliceHeaderSpacing = 0;
- h264type.nBFrames = 0; // No B frames support yet
- h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
- if (h264type.nPFrames == 0) {
- h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
- }
-
// Check profile and level parameters
CodecProfileLevel defaultProfileLevel, profileLevel;
defaultProfileLevel.mProfile = h264type.eProfile;
@@ -1312,8 +1305,14 @@
h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
+ h264type.nSliceHeaderSpacing = 0;
h264type.bUseHadamard = OMX_TRUE;
h264type.nRefFrames = 1;
+ h264type.nBFrames = 0;
+ h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
+ if (h264type.nPFrames == 0) {
+ h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
+ }
h264type.nRefIdx10ActiveMinus1 = 0;
h264type.nRefIdx11ActiveMinus1 = 0;
h264type.bEntropyCodingCABAC = OMX_FALSE;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index bc04e8c..9085f10 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -871,6 +871,14 @@
// check space first
if (mSendObjectFileSize > storage->getFreeSpace())
return MTP_RESPONSE_STORAGE_FULL;
+ uint64_t maxFileSize = storage->getMaxFileSize();
+ // check storage max file size
+ if (maxFileSize != 0) {
+ // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
+ // is >= 0xFFFFFFFF
+ if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
+ return MTP_RESPONSE_OBJECT_TOO_LARGE;
+ }
LOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
diff --git a/media/mtp/MtpStorage.cpp b/media/mtp/MtpStorage.cpp
index fef8066..941e303 100644
--- a/media/mtp/MtpStorage.cpp
+++ b/media/mtp/MtpStorage.cpp
@@ -33,11 +33,13 @@
namespace android {
MtpStorage::MtpStorage(MtpStorageID id, const char* filePath,
- const char* description, uint64_t reserveSpace, bool removable)
+ const char* description, uint64_t reserveSpace,
+ bool removable, uint64_t maxFileSize)
: mStorageID(id),
mFilePath(filePath),
mDescription(description),
mMaxCapacity(0),
+ mMaxFileSize(maxFileSize),
mReserveSpace(reserveSpace),
mRemovable(removable)
{
diff --git a/media/mtp/MtpStorage.h b/media/mtp/MtpStorage.h
index 3e4f40d..e5a2e57 100644
--- a/media/mtp/MtpStorage.h
+++ b/media/mtp/MtpStorage.h
@@ -31,6 +31,7 @@
MtpString mFilePath;
MtpString mDescription;
uint64_t mMaxCapacity;
+ uint64_t mMaxFileSize;
// amount of free space to leave unallocated
uint64_t mReserveSpace;
bool mRemovable;
@@ -38,7 +39,7 @@
public:
MtpStorage(MtpStorageID id, const char* filePath,
const char* description, uint64_t reserveSpace,
- bool removable);
+ bool removable, uint64_t maxFileSize);
virtual ~MtpStorage();
inline MtpStorageID getStorageID() const { return mStorageID; }
@@ -50,6 +51,7 @@
const char* getDescription() const;
inline const char* getPath() const { return (const char *)mFilePath; }
inline bool isRemovable() const { return mRemovable; }
+ inline uint64_t getMaxFileSize() const { return mMaxFileSize; }
};
}; // namespace android
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java
index 5120694..afe2001 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java
@@ -1335,16 +1335,19 @@
@LargeTest
public void testEffectKenBurn() throws Exception {
// Test ken burn effect using a JPEG file.
- testEffectKenBurn(INPUT_FILE_PATH + "IMG_640x480.jpg");
+ testEffectKenBurn(INPUT_FILE_PATH + "IMG_640x480.jpg",
+ "mediaImageItem1");
// Test ken burn effect using a PNG file
- testEffectKenBurn(INPUT_FILE_PATH + "IMG_640x480.png");
+ testEffectKenBurn(INPUT_FILE_PATH + "IMG_640x480.png",
+ "mediaImageItem2");
}
- private void testEffectKenBurn(final String imageItemFileName) throws Exception {
+ private void testEffectKenBurn(final String imageItemFileName,
+ final String MediaId) throws Exception {
final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
+ mVideoEditorHelper.createMediaItem(mVideoEditor, MediaId,
imageItemFileName, 5000, imageItemRenderingMode);
mVideoEditor.addMediaItem(mediaImageItem);
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
new file mode 100644
index 0000000..ab5f4bd
--- /dev/null
+++ b/opengl/tests/EGLTest/Android.mk
@@ -0,0 +1,41 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_MODULE := EGL_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ EGL_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libEGL \
+ libcutils \
+ libstlport \
+ libutils \
+
+LOCAL_STATIC_LIBRARIES := \
+ libgtest \
+ libgtest_main \
+
+LOCAL_C_INCLUDES := \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport \
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
new file mode 100644
index 0000000..337ad33
--- /dev/null
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/String8.h>
+
+#include <EGL/egl.h>
+
+namespace android {
+
+class EGLTest : public ::testing::Test {
+protected:
+ EGLDisplay mEglDisplay;
+
+protected:
+ EGLTest() :
+ mEglDisplay(EGL_NO_DISPLAY) {
+ }
+
+ virtual void SetUp() {
+ mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ RecordProperty("EglVersionMajor", majorVersion);
+ RecordProperty("EglVersionMajor", minorVersion);
+ }
+
+ virtual void TearDown() {
+ EGLBoolean success = eglTerminate(mEglDisplay);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ }
+};
+
+TEST_F(EGLTest, DISABLED_EGLConfigEightBitFirst) {
+
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+ EGLint attrs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_GE(numConfigs, 1);
+
+ EGLint components[3];
+
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EXPECT_GE(components[0], 8);
+ EXPECT_GE(components[1], 8);
+ EXPECT_GE(components[2], 8);
+}
+
+TEST_F(EGLTest, EGLConfigRGBA8888First) {
+
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+ EGLint attrs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_NONE
+ };
+
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_GE(numConfigs, 1);
+
+ EGLint components[4];
+
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+ ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EXPECT_GE(components[0], 8);
+ EXPECT_GE(components[1], 8);
+ EXPECT_GE(components[2], 8);
+ EXPECT_GE(components[3], 8);
+}
+
+
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 47ab150..afe4246 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -16,17 +16,6 @@
package com.android.providers.settings;
-import com.android.internal.content.PackageHelper;
-import com.android.internal.telephony.BaseCommands;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.util.XmlUtils;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternView;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
@@ -47,6 +36,17 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.telephony.BaseCommands;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternView;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
@@ -63,7 +63,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 65;
+ private static final int DATABASE_VERSION = 66;
private Context mContext;
@@ -839,6 +839,28 @@
upgradeVersion = 65;
}
+ if (upgradeVersion == 65) {
+ /*
+ * Animations are removed from Settings. Turned on by default
+ */
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ db.execSQL("DELETE FROM system WHERE name='"
+ + Settings.System.WINDOW_ANIMATION_SCALE + "'");
+ db.execSQL("DELETE FROM system WHERE name='"
+ + Settings.System.TRANSITION_ANIMATION_SCALE + "'");
+ stmt = db.compileStatement("INSERT INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadDefaultAnimationSettings(stmt);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 66;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index 386182d..28ef239 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -29,21 +29,17 @@
android:background="@drawable/status_bar_recents_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_alignParentBottom="true"
- android:paddingBottom="@*android:dimen/status_bar_height"
- android:clipToPadding="false"
- android:clipChildren="false">
+ android:layout_alignParentBottom="true">
<LinearLayout android:id="@+id/recents_glow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="0dp"
android:layout_gravity="bottom"
android:orientation="horizontal"
- android:clipToPadding="false"
android:clipChildren="false"
- >
- <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
+ android:layout_marginTop="@*android:dimen/status_bar_height">
+ <com.android.systemui.recent.RecentsVerticalScrollView
+ android:id="@+id/recents_container"
android:layout_width="@dimen/status_bar_recents_width"
android:layout_height="wrap_content"
android:layout_marginRight="0dp"
@@ -51,7 +47,7 @@
android:stackFromBottom="true"
android:fadingEdge="vertical"
android:scrollbars="none"
- android:fadingEdgeLength="20dip"
+ android:fadingEdgeLength="@*android:dimen/status_bar_height"
android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:layout_gravity="bottom|left"
android:clipToPadding="false"
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Constants.java b/packages/SystemUI/src/com/android/systemui/recent/Constants.java
new file mode 100644
index 0000000..8252a9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/Constants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recent;
+
+public class Constants {
+ static final int MAX_ESCAPE_ANIMATION_DURATION = 500; // in ms
+ static final int SNAP_BACK_DURATION = 250; // in ms
+ static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it in dp/s
+ public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width where fade starts
+ static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width beyond which alpha->0
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 3dbcc59..f984aac 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -25,6 +25,7 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.RectF;
import android.util.AttributeSet;
@@ -33,6 +34,7 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.HorizontalScrollView;
@@ -42,12 +44,9 @@
public class RecentsHorizontalScrollView extends HorizontalScrollView
implements View.OnClickListener, View.OnTouchListener {
- private static final float FADE_CONSTANT = 0.5f;
- private static final int SNAP_BACK_DURATION = 250;
- private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
- private static final String TAG = RecentsPanelView.TAG;
- private static final float THRESHHOLD = 50;
private static final boolean DEBUG_INVALIDATE = false;
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final boolean DEBUG = RecentsPanelView.DEBUG;
private LinearLayout mLinearLayout;
private ActivityDescriptionAdapter mAdapter;
private RecentsCallback mCallback;
@@ -56,6 +55,8 @@
private float mLastY;
private boolean mDragging;
private VelocityTracker mVelocityTracker;
+ private float mDensityScale;
+ private float mPagingTouchSlop;
public RecentsHorizontalScrollView(Context context) {
this(context, null);
@@ -63,6 +64,8 @@
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
}
private int scrollPositionOfMostRecent() {
@@ -101,7 +104,8 @@
case MotionEvent.ACTION_MOVE:
float delta = ev.getY() - mLastY;
- if (Math.abs(delta) > THRESHHOLD) {
+ if (DEBUG) Log.v(TAG, "ACTION_MOVE : " + delta);
+ if (Math.abs(delta) > mPagingTouchSlop) {
mDragging = true;
}
break;
@@ -114,13 +118,14 @@
}
private float getAlphaForOffset(View view, float thumbHeight) {
- final float fadeHeight = FADE_CONSTANT * thumbHeight;
+ final float fadeHeight = Constants.ALPHA_FADE_END * thumbHeight;
float result = 1.0f;
- if (view.getY() >= thumbHeight) {
- result = 1.0f - (view.getY() - thumbHeight) / fadeHeight;
- } else if (view.getY() < 0.0f) {
- result = 1.0f + (thumbHeight + view.getY()) / fadeHeight;
+ if (view.getY() >= thumbHeight * Constants.ALPHA_FADE_START) {
+ result = 1.0f - (view.getY() - thumbHeight * Constants.ALPHA_FADE_START) / fadeHeight;
+ } else if (view.getY() < thumbHeight * (1.0f - Constants.ALPHA_FADE_START)) {
+ result = 1.0f + (thumbHeight * Constants.ALPHA_FADE_START + view.getY()) / fadeHeight;
}
+ if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -155,12 +160,13 @@
final float velocityY = velocityTracker.getYVelocity();
final float curY = animView.getY();
final float newY = (velocityY >= 0.0f ? 1 : -1) * animView.getHeight();
-
+ final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
if (Math.abs(velocityY) > Math.abs(velocityX)
- && Math.abs(velocityY) > ESCAPE_VELOCITY
+ && Math.abs(velocityY) > maxVelocity
&& (velocityY >= 0.0f) == (animView.getY() >= 0)) {
- final long duration =
+ long duration =
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
+ duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
anim.setInterpolator(new LinearInterpolator());
final int swipeDirection = animView.getY() >= 0.0f ?
@@ -181,9 +187,10 @@
});
anim.setDuration(duration);
} else { // Animate back to position
- final long duration = Math.abs(velocityY) > 0.0f ?
+ long duration = Math.abs(velocityY) > 0.0f ?
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
- : SNAP_BACK_DURATION;
+ : Constants.SNAP_BACK_DURATION;
+ duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
anim.setInterpolator(new DecelerateInterpolator(2.0f));
anim.setDuration(duration);
@@ -241,8 +248,15 @@
setOverScrollEffectPadding(leftPadding, 0);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
+ }
+
private void setOverScrollEffectPadding(int leftPadding, int i) {
- // TODO Add to RecentsHorizontalScrollView
+ // TODO Add to (Vertical)ScrollView
}
@Override
@@ -255,7 +269,7 @@
// This has to happen post-layout, so run it "in the future"
post(new Runnable() {
public void run() {
- scrollTo(0, mLastScrollPosition);
+ scrollTo(mLastScrollPosition, 0);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 6190c9b..a55fe9c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -417,11 +417,11 @@
mActivityDescriptions = getRecentTasks();
mListAdapter.notifyDataSetInvalidated();
if (mActivityDescriptions.size() > 0) {
- Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
+ if (DEBUG) Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
updateUiElements(getResources().getConfiguration());
} else {
// Immediately hide this panel
- Log.v(TAG, "Nothing to show");
+ if (DEBUG) Log.v(TAG, "Nothing to show");
hide(false);
}
}
@@ -436,7 +436,7 @@
paint.setAlpha(255);
final int srcWidth = thumbnail.getWidth();
final int srcHeight = thumbnail.getHeight();
- Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
+ if (DEBUG) Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
canvas.drawBitmap(thumbnail,
new Rect(0, 0, srcWidth-1, srcHeight-1),
new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
@@ -486,7 +486,7 @@
public void handleSwipe(View view, int direction) {
ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
- Log.v(TAG, "Jettison " + ad.label);
+ if (DEBUG) Log.v(TAG, "Jettison " + ad.label);
mActivityDescriptions.remove(ad);
// Handled by widget containers to enable LayoutTransitions properly
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 6a962cb..27bb0b5 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -25,6 +25,7 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.RectF;
import android.util.AttributeSet;
@@ -33,6 +34,7 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
@@ -42,12 +44,9 @@
public class RecentsVerticalScrollView extends ScrollView
implements View.OnClickListener, View.OnTouchListener {
- private static final float FADE_CONSTANT = 0.5f;
- private static final int SNAP_BACK_DURATION = 250;
- private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
private static final String TAG = RecentsPanelView.TAG;
- private static final float THRESHHOLD = 50;
private static final boolean DEBUG_INVALIDATE = false;
+ private static final boolean DEBUG = RecentsPanelView.DEBUG;
private LinearLayout mLinearLayout;
private ActivityDescriptionAdapter mAdapter;
private RecentsCallback mCallback;
@@ -56,6 +55,8 @@
private float mLastX;
private boolean mDragging;
private VelocityTracker mVelocityTracker;
+ private float mDensityScale;
+ private float mPagingTouchSlop;
public RecentsVerticalScrollView(Context context) {
this(context, null);
@@ -63,6 +64,8 @@
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
}
private int scrollPositionOfMostRecent() {
@@ -101,8 +104,8 @@
case MotionEvent.ACTION_MOVE:
float delta = ev.getX() - mLastX;
- Log.v(TAG, "ACTION_MOVE : " + delta);
- if (Math.abs(delta) > THRESHHOLD) {
+ if (DEBUG) Log.v(TAG, "ACTION_MOVE : " + delta);
+ if (Math.abs(delta) > mPagingTouchSlop) {
mDragging = true;
}
break;
@@ -115,14 +118,14 @@
}
private float getAlphaForOffset(View view, float thumbWidth) {
- final float fadeWidth = FADE_CONSTANT * thumbWidth;
+ final float fadeWidth = Constants.ALPHA_FADE_END * thumbWidth;
float result = 1.0f;
- if (view.getX() >= thumbWidth) {
- result = 1.0f - (view.getX() - thumbWidth) / fadeWidth;
- } else if (view.getX() < 0.0f) {
- result = 1.0f + (thumbWidth + view.getX()) / fadeWidth;
+ if (view.getX() >= thumbWidth*Constants.ALPHA_FADE_START) {
+ result = 1.0f - (view.getX() - thumbWidth*Constants.ALPHA_FADE_START) / fadeWidth;
+ } else if (view.getX() < thumbWidth* (1.0f - Constants.ALPHA_FADE_START)) {
+ result = 1.0f + (thumbWidth*Constants.ALPHA_FADE_START + view.getX()) / fadeWidth;
}
- Log.v(TAG, "FADE AMOUNT: " + result);
+ if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -157,12 +160,13 @@
final float velocityY = velocityTracker.getYVelocity();
final float curX = animView.getX();
final float newX = (velocityX >= 0.0f ? 1 : -1) * animView.getWidth();
-
+ final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
if (Math.abs(velocityX) > Math.abs(velocityY)
- && Math.abs(velocityX) > ESCAPE_VELOCITY
+ && Math.abs(velocityX) > maxVelocity
&& (velocityX > 0.0f) == (animView.getX() >= 0)) {
- final long duration =
+ long duration =
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
+ duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
anim.setInterpolator(new LinearInterpolator());
final int swipeDirection = animView.getX() >= 0.0f ?
@@ -183,9 +187,10 @@
});
anim.setDuration(duration);
} else { // Animate back to position
- final long duration = Math.abs(velocityX) > 0.0f ?
+ long duration = Math.abs(velocityX) > 0.0f ?
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
- : SNAP_BACK_DURATION;
+ : Constants.SNAP_BACK_DURATION;
+ duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
anim = ObjectAnimator.ofFloat(animView, "x", animView.getX(), 0.0f);
anim.setInterpolator(new DecelerateInterpolator(4.0f));
anim.setDuration(duration);
@@ -243,6 +248,13 @@
setOverScrollEffectPadding(leftPadding, 0);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
+ }
+
private void setOverScrollEffectPadding(int leftPadding, int i) {
// TODO Add to (Vertical)ScrollView
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5eacad7..b50fd81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -307,7 +307,7 @@
mDateView.setVisibility(View.INVISIBLE);
// Recents Panel
- initializeRecentsPanel();
+ updateRecentsPanel();
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -338,7 +338,7 @@
return lp;
}
- protected void initializeRecentsPanel() {
+ protected void updateRecentsPanel() {
// Recents Panel
boolean visible = false;
if (mRecentsPanel != null) {
@@ -385,9 +385,9 @@
// For small-screen devices (read: phones) that lack hardware navigation buttons
private void addNavigationBar() {
if (mNavigationBarView == null) return;
-
+
mNavigationBarView.reorient();
-
+
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
WindowManagerImpl.getDefault().addView(
@@ -396,7 +396,7 @@
private void repositionNavigationBar() {
if (mNavigationBarView == null) return;
-
+
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
@@ -656,7 +656,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- initializeRecentsPanel();
+ updateRecentsPanel();
}
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index f862d01..75e799c 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -29,7 +29,9 @@
import android.os.SystemClock;
import android.security.KeyStore;
import android.telephony.TelephonyManager;
+import android.text.Editable;
import android.text.InputType;
+import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -120,15 +122,6 @@
}
});
- // We don't currently use the IME for PIN mode, but this will make it work if we ever do...
- if (!mIsAlpha) {
- mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
- | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
- } else {
- mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
- | InputType.TYPE_TEXT_VARIATION_PASSWORD);
- }
-
mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
mEmergencyCallButton.setOnClickListener(this);
mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
@@ -151,14 +144,17 @@
mPasswordEntry.requestFocus();
- // This allows keyboards with overlapping qwerty/numeric keys to choose just the
- // numeric keys.
+ // This allows keyboards with overlapping qwerty/numeric keys to choose just numeric keys.
if (mIsAlpha) {
mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD);
// mStatusView.setHelpMessage(R.string.keyguard_password_enter_password_code,
// StatusView.LOCK_ICON);
} else {
mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
//mStatusView.setHelpMessage(R.string.keyguard_password_enter_pin_code,
// StatusView.LOCK_ICON);
}
@@ -179,6 +175,19 @@
//mUpdateMonitor.registerSimStateCallback(this);
resetStatusInfo();
+
+ // Poke the wakelock any time the text is modified
+ mPasswordEntry.addTextChangedListener(new TextWatcher() {
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ public void afterTextChanged(Editable s) {
+ mCallback.pokeWakelock();
+ }
+ });
}
@Override
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 1d247bd..4d721f6 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "AudioSRC"
+
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
@@ -22,8 +24,6 @@
#include "AudioResampler.h"
#include "AudioResamplerCubic.h"
-#define LOG_TAG "AudioSRC"
-
namespace android {
// ----------------------------------------------------------------------------
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6afccec..786f2fa 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -224,6 +224,7 @@
public PackageInfo pkgInfo;
public int pmToken; // in post-install restore, the PM's token for this transaction
public boolean needFullBackup;
+ public String[] filterSet;
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
@@ -233,6 +234,7 @@
pkgInfo = _pkg;
pmToken = _pmToken;
needFullBackup = _needFullBackup;
+ filterSet = null;
}
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
@@ -243,6 +245,18 @@
pkgInfo = null;
pmToken = 0;
needFullBackup = _needFullBackup;
+ filterSet = null;
+ }
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
+ String[] _filterSet, boolean _needFullBackup) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ pkgInfo = null;
+ pmToken = 0;
+ needFullBackup = _needFullBackup;
+ filterSet = _filterSet;
}
}
@@ -404,7 +418,7 @@
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
(new PerformRestoreTask(params.transport, params.observer,
params.token, params.pkgInfo, params.pmToken,
- params.needFullBackup)).run();
+ params.needFullBackup, params.filterSet)).run();
break;
}
@@ -3020,6 +3034,7 @@
private File mStateDir;
private int mPmToken;
private boolean mNeedFullBackup;
+ private HashSet<String> mFilterSet;
class RestoreRequest {
public PackageInfo app;
@@ -3033,7 +3048,7 @@
PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
long restoreSetToken, PackageInfo targetPackage, int pmToken,
- boolean needFullBackup) {
+ boolean needFullBackup, String[] filterSet) {
mTransport = transport;
mObserver = observer;
mToken = restoreSetToken;
@@ -3041,6 +3056,15 @@
mPmToken = pmToken;
mNeedFullBackup = needFullBackup;
+ if (filterSet != null) {
+ mFilterSet = new HashSet<String>();
+ for (String pkg : filterSet) {
+ mFilterSet.add(pkg);
+ }
+ } else {
+ mFilterSet = null;
+ }
+
try {
mStateDir = new File(mBaseStateDir, transport.transportDirName());
} catch (RemoteException e) {
@@ -3052,7 +3076,8 @@
long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
+ " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
- + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
+ + " mTargetPackage=" + mTargetPackage + " mFilterSet=" + mFilterSet
+ + " mPmToken=" + mPmToken);
PackageManagerBackupAgent pmAgent = null;
int error = -1; // assume error
@@ -3071,6 +3096,22 @@
List<PackageInfo> agentPackages = allAgentPackages();
if (mTargetPackage == null) {
+ // if there's a filter set, strip out anything that isn't
+ // present before proceeding
+ if (mFilterSet != null) {
+ for (int i = agentPackages.size() - 1; i >= 0; i--) {
+ final PackageInfo pkg = agentPackages.get(i);
+ if (! mFilterSet.contains(pkg.packageName)) {
+ agentPackages.remove(i);
+ }
+ }
+ if (DEBUG) {
+ Slog.i(TAG, "Post-filter package set for restore:");
+ for (PackageInfo p : agentPackages) {
+ Slog.i(TAG, " " + p);
+ }
+ }
+ }
restorePackages.addAll(agentPackages);
} else {
// Just one package to attempt restore of
@@ -4266,6 +4307,67 @@
return -1;
}
+ public synchronized int restoreSome(long token, IRestoreObserver observer,
+ String[] packages) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
+
+ if (DEBUG) {
+ StringBuilder b = new StringBuilder(128);
+ b.append("restoreSome token=");
+ b.append(Long.toHexString(token));
+ b.append(" observer=");
+ b.append(observer.toString());
+ b.append(" packages=");
+ if (packages == null) {
+ b.append("null");
+ } else {
+ b.append('{');
+ boolean first = true;
+ for (String s : packages) {
+ if (!first) {
+ b.append(", ");
+ } else first = false;
+ b.append(s);
+ }
+ b.append('}');
+ }
+ Slog.d(TAG, b.toString());
+ }
+
+ if (mEnded) {
+ throw new IllegalStateException("Restore session already ended");
+ }
+
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Slog.e(TAG, "Ignoring restoreAll() with no restore set");
+ return -1;
+ }
+
+ if (mPackageName != null) {
+ Slog.e(TAG, "Ignoring restoreAll() on single-package session");
+ return -1;
+ }
+
+ synchronized (mQueueLock) {
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ long oldId = Binder.clearCallingIdentity();
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token,
+ packages, true);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
+ }
+ }
+ }
+
+ Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
+ return -1;
+ }
+
public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b98d2a2..41450d2 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1602,8 +1602,10 @@
if (linkProperties != null) {
String iface = linkProperties.getInterfaceName();
if (TextUtils.isEmpty(iface) == false) {
- if (DBG) log("resetConnections(" + iface + ")");
- NetworkUtils.resetConnections(iface);
+ if (DBG) {
+ log("resetConnections(" + iface + ", NetworkUtils.RESET_ALL_ADDRESSES)");
+ }
+ NetworkUtils.resetConnections(iface, NetworkUtils.RESET_ALL_ADDRESSES);
}
}
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 54e5432..2e54c99 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1075,18 +1075,22 @@
com.android.internal.R.styleable.Storage_mtpReserve, 0);
boolean allowMassStorage = a.getBoolean(
com.android.internal.R.styleable.Storage_allowMassStorage, false);
+ // resource parser does not support longs, so XML value is in megabytes
+ long maxFileSize = a.getInt(
+ com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L;
Slog.d(TAG, "got storage path: " + path + " description: " + description +
" primary: " + primary + " removable: " + removable +
" emulated: " + emulated + " mtpReserve: " + mtpReserve +
- " allowMassStorage: " + allowMassStorage);
+ " allowMassStorage: " + allowMassStorage +
+ " maxFileSize: " + maxFileSize);
if (path == null || description == null) {
Slog.e(TAG, "path or description is null in readStorageList");
} else {
String pathString = path.toString();
StorageVolume volume = new StorageVolume(pathString,
description.toString(), removable, emulated,
- mtpReserve, allowMassStorage);
+ mtpReserve, allowMassStorage, maxFileSize);
if (primary) {
if (mPrimaryVolume == null) {
mPrimaryVolume = volume;
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index 15f22c0..f7fe39e 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -16,8 +16,6 @@
package com.android.server;
-import com.android.internal.telephony.TelephonyIntents;
-
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -28,7 +26,6 @@
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.SntpClient;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -36,12 +33,10 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
-import android.util.Slog;
+import android.util.NtpTrustedTime;
+import android.util.TrustedTime;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Properties;
+import com.android.internal.telephony.TelephonyIntents;
/**
* Monitors the network time and updates the system time if it is out of sync
@@ -68,14 +63,11 @@
private static final long POLLING_INTERVAL_SHORTER_MS = 60 * 1000L; // 60 seconds
/** Number of times to try again */
private static final int TRY_AGAIN_TIMES_MAX = 3;
- /** How long to wait for the NTP server to respond. */
- private static final int MAX_NTP_FETCH_WAIT_MS = 20 * 1000;
/** If the time difference is greater than this threshold, then update the time. */
private static final int TIME_ERROR_THRESHOLD_MS = 5 * 1000;
private static final String ACTION_POLL =
"com.android.server.NetworkTimeUpdateService.action.POLL";
- private static final String PROPERTIES_FILE = "/etc/gps.conf";
private static int POLL_REQUEST = 0;
private static final long NOT_SET = -1;
@@ -84,14 +76,14 @@
private long mNitzZoneSetTime = NOT_SET;
private Context mContext;
+ private TrustedTime mTime;
+
// NTP lookup is done on this thread and handler
private Handler mHandler;
private HandlerThread mThread;
private AlarmManager mAlarmManager;
private PendingIntent mPendingPollIntent;
private SettingsObserver mSettingsObserver;
- // Address of the NTP server
- private String mNtpServer;
// The last time that we successfully fetched the NTP time.
private long mLastNtpFetchTime = NOT_SET;
// Keeps track of how many quick attempts were made to fetch NTP time.
@@ -101,6 +93,7 @@
public NetworkTimeUpdateService(Context context) {
mContext = context;
+ mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
@@ -108,12 +101,6 @@
/** Initialize the receivers and initiate the first NTP request */
public void systemReady() {
- mNtpServer = getNtpServerAddress();
- if (mNtpServer == null) {
- Slog.e(TAG, "NTP server address not found, not syncing to NTP time");
- return;
- }
-
registerForTelephonyIntents();
registerForAlarms();
registerForConnectivityIntents();
@@ -128,27 +115,6 @@
mSettingsObserver.observe(mContext);
}
- private String getNtpServerAddress() {
- String serverAddress = null;
- FileInputStream stream = null;
- try {
- Properties properties = new Properties();
- File file = new File(PROPERTIES_FILE);
- stream = new FileInputStream(file);
- properties.load(stream);
- serverAddress = properties.getProperty("NTP_SERVER", null);
- } catch (IOException e) {
- Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (Exception e) {}
- }
- }
- return serverAddress;
- }
-
private void registerForTelephonyIntents() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
@@ -189,9 +155,15 @@
if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + POLLING_INTERVAL_MS
|| event == EVENT_AUTO_TIME_CHANGED) {
if (DBG) Log.d(TAG, "Before Ntp fetch");
- long ntp = getNtpTime();
- if (DBG) Log.d(TAG, "Ntp = " + ntp);
- if (ntp > 0) {
+
+ // force refresh NTP cache when outdated
+ if (mTime.getCacheAge() >= POLLING_INTERVAL_MS) {
+ mTime.forceRefresh();
+ }
+
+ // only update when NTP time is fresh
+ if (mTime.getCacheAge() < POLLING_INTERVAL_MS) {
+ final long ntp = mTime.currentTimeMillis();
mTryAgainCounter = 0;
mLastNtpFetchTime = SystemClock.elapsedRealtime();
if (Math.abs(ntp - currentTime) > TIME_ERROR_THRESHOLD_MS) {
@@ -232,15 +204,6 @@
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
}
- private long getNtpTime() {
- SntpClient client = new SntpClient();
- if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT_MS)) {
- return client.getNtpTime();
- } else {
- return 0;
- }
- }
-
/**
* Checks if the user prefers to automatically set the time.
*/
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index d81dfdb..24d4dd3 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -16,9 +16,6 @@
package com.android.server;
-import com.android.internal.R;
-import com.android.internal.telephony.TelephonyProperties;
-
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -54,6 +51,9 @@
import android.util.Slog;
import android.util.TrustedTime;
+import com.android.internal.R;
+import com.android.internal.telephony.TelephonyProperties;
+
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileDescriptor;
@@ -63,7 +63,6 @@
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
-import java.util.Properties;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -87,7 +86,6 @@
private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000;
- private static final long MAX_NTP_FETCH_WAIT = 20 * 1000;
private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE;
@@ -127,8 +125,6 @@
private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
- private static final String PROPERTIES_FILE = "/etc/gps.conf";
-
private Intent mPollStickyBroadcast;
private TrustedTime mTime;
@@ -139,8 +135,7 @@
}
public ThrottleService(Context context) {
- // TODO: move to using cached NtpTrustedTime
- this(context, getNetworkManagementService(), new NtpTrustedTime(),
+ this(context, getNetworkManagementService(), NtpTrustedTime.getInstance(context),
context.getResources().getString(R.string.config_datause_iface));
}
@@ -341,26 +336,6 @@
}
}, new IntentFilter(ACTION_RESET));
- FileInputStream stream = null;
- try {
- Properties properties = new Properties();
- File file = new File(PROPERTIES_FILE);
- stream = new FileInputStream(file);
- properties.load(stream);
- final String ntpServer = properties.getProperty("NTP_SERVER", null);
- if (mTime instanceof NtpTrustedTime) {
- ((NtpTrustedTime) mTime).setNtpServer(ntpServer, MAX_NTP_FETCH_WAIT);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (Exception e) {}
- }
- }
-
// use a new thread as we don't want to stall the system for file writes
mThread = new HandlerThread(TAG);
mThread.start();
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 4fa3bda..c813d37 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -32,7 +32,6 @@
import android.location.LocationProvider;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.SntpClient;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -51,6 +50,7 @@
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
+import android.util.NtpTrustedTime;
import android.util.SparseIntArray;
import com.android.internal.app.IBatteryStats;
@@ -61,7 +61,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.io.StringBufferInputStream;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map.Entry;
@@ -235,13 +235,13 @@
// properties loaded from PROPERTIES_FILE
private Properties mProperties;
- private String mNtpServer;
private String mSuplServerHost;
private int mSuplServerPort;
private String mC2KServerHost;
private int mC2KServerPort;
private final Context mContext;
+ private final NtpTrustedTime mNtpTime;
private final ILocationManager mLocationManager;
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
private Bundle mLocationExtras = new Bundle();
@@ -286,10 +286,6 @@
// current setting - 5 minutes
private static final long RETRY_INTERVAL = 5*60*1000;
- // to avoid injecting bad NTP time, we reject any time fixes that differ from system time
- // by more than 5 minutes.
- private static final long MAX_NTP_SYSTEM_TIME_OFFSET = 5*60*1000;
-
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
if (listener == null) {
@@ -378,6 +374,7 @@
public GpsLocationProvider(Context context, ILocationManager locationManager) {
mContext = context;
+ mNtpTime = NtpTrustedTime.getInstance(context);
mLocationManager = locationManager;
mNIHandler = new GpsNetInitiatedHandler(context);
@@ -418,7 +415,6 @@
FileInputStream stream = new FileInputStream(file);
mProperties.load(stream);
stream.close();
- mNtpServer = mProperties.getProperty("NTP_SERVER", null);
mSuplServerHost = mProperties.getProperty("SUPL_HOST");
String portString = mProperties.getProperty("SUPL_PORT");
@@ -530,13 +526,18 @@
}
mInjectNtpTimePending = false;
- SntpClient client = new SntpClient();
long delay;
- if (client.requestTime(mNtpServer, 10000)) {
- long time = client.getNtpTime();
- long timeReference = client.getNtpTimeReference();
- int certainty = (int)(client.getRoundTripTime()/2);
+ // force refresh NTP cache when outdated
+ if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
+ mNtpTime.forceRefresh();
+ }
+
+ // only update when NTP time is fresh
+ if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
+ long time = mNtpTime.getCachedNtpTime();
+ long timeReference = mNtpTime.getCachedNtpTimeReference();
+ long certainty = mNtpTime.getCacheCertainty();
long now = System.currentTimeMillis();
Log.d(TAG, "NTP server returned: "
@@ -545,7 +546,7 @@
+ " certainty: " + certainty
+ " system time offset: " + (time - now));
- native_inject_time(time, timeReference, certainty);
+ native_inject_time(time, timeReference, (int) certainty);
delay = NTP_INTERVAL;
} else {
if (DEBUG) Log.d(TAG, "requestTime failed");
@@ -1395,7 +1396,7 @@
Properties extraProp = new Properties();
try {
- extraProp.load(new StringBufferInputStream(extras));
+ extraProp.load(new StringReader(extras));
}
catch (IOException e)
{
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 2a17cbe..d23d0f4 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -204,9 +204,8 @@
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats,
INetworkManagementService networkManagement) {
- // TODO: move to using cached NtpTrustedTime
this(context, activityManager, powerManager, networkStats, networkManagement,
- new NtpTrustedTime(), getSystemDir());
+ NtpTrustedTime.getInstance(context), getSystemDir());
}
private static File getSystemDir() {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index b4bd176..b6834f6 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -27,7 +27,6 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
-import static android.provider.Settings.Secure.NETSTATS_ENABLED;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
@@ -71,7 +70,6 @@
import android.util.TrustedTime;
import com.android.internal.os.AtomicFile;
-import com.android.server.NativeDaemonConnectorException;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -175,9 +173,8 @@
public NetworkStatsService(
Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
- // TODO: move to using cached NtpTrustedTime
- this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir(),
- new DefaultNetworkStatsSettings(context));
+ this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
+ getSystemDir(), new DefaultNetworkStatsSettings(context));
}
private static File getSystemDir() {
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index d645160..1ab570a 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -630,20 +630,20 @@
}
/* opens the currently attached USB accessory */
- public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
- UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
- if (currentAccessory == null) {
- throw new IllegalArgumentException("no accessory attached");
- }
- if (!currentAccessory.equals(accessory)) {
- String error = accessory.toString()
- + " does not match current accessory "
- + currentAccessory;
- throw new IllegalArgumentException(error);
- }
- mSettingsManager.checkPermission(accessory);
- return nativeOpenAccessory();
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
+ if (currentAccessory == null) {
+ throw new IllegalArgumentException("no accessory attached");
}
+ if (!currentAccessory.equals(accessory)) {
+ String error = accessory.toString()
+ + " does not match current accessory "
+ + currentAccessory;
+ throw new IllegalArgumentException(error);
+ }
+ mSettingsManager.checkPermission(accessory);
+ return nativeOpenAccessory();
+ }
public void setCurrentFunction(String function, boolean makeDefault) {
if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 33125c4..7bf3e0a 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -99,6 +99,31 @@
mMaxViewportDims[0] : mMaxViewportDims[1];
}
+static status_t selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig)
+{
+ EGLConfig config = NULL;
+ EGLint numConfigs = -1, n=0;
+ eglGetConfigs(dpy, NULL, 0, &numConfigs);
+ EGLConfig* const configs = new EGLConfig[numConfigs];
+ eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+ for (int i=0 ; i<n ; i++) {
+ EGLint nativeVisualId = 0;
+ eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+ if (nativeVisualId>0 && format == nativeVisualId) {
+ *outConfig = configs[i];
+ delete [] configs;
+ return NO_ERROR;
+ }
+ }
+ delete [] configs;
+ return NAME_NOT_FOUND;
+}
+
+
void DisplayHardware::init(uint32_t dpy)
{
mNativeWindow = new FramebufferNativeWindow();
@@ -108,6 +133,9 @@
exit(0);
}
+ int format;
+ ANativeWindow const * const window = mNativeWindow.get();
+ window->query(window, NATIVE_WINDOW_FORMAT, &format);
mDpiX = mNativeWindow->xdpi;
mDpiY = mNativeWindow->ydpi;
mRefreshRate = fbDev->fps;
@@ -116,11 +144,13 @@
EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
+ EGLBoolean result;
+ status_t err;
// initialize EGL
EGLint attribs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_NONE, 0,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE, 0,
EGL_NONE
};
@@ -141,9 +171,8 @@
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
- EGLConfig config;
- status_t err = EGLUtils::selectConfigForNativeWindow(
- display, attribs, mNativeWindow.get(), &config);
+ EGLConfig config = NULL;
+ err = selectConfigForPixelFormat(display, attribs, format, &config);
LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
EGLint r,g,b,a;
@@ -224,7 +253,11 @@
* Gather OpenGL ES extensions
*/
- eglMakeCurrent(display, surface, surface, context);
+ result = eglMakeCurrent(display, surface, surface, context);
+ if (!result) {
+ LOGE("Couldn't create a working GLES context. check logs. exiting...");
+ exit(0);
+ }
GLExtensions& extensions(GLExtensions::getInstance());
extensions.initWithGLStrings(
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index bcd8c83..c86c659 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -228,13 +228,18 @@
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
const bool transformed = tr.transformed();
-
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t hw_h = hw.getHeight();
+
uint32_t w = s.w;
uint32_t h = s.h;
tr.transform(mVertices[0], 0, 0);
tr.transform(mVertices[1], 0, h);
tr.transform(mVertices[2], w, h);
tr.transform(mVertices[3], w, 0);
+ for (size_t i=0 ; i<4 ; i++)
+ mVertices[i][1] = hw_h - mVertices[i][1];
+
if (UNLIKELY(transformed)) {
// NOTE: here we could also punt if we have too many rectangles
// in the transparent region
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cccab4a..b0881a4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -276,7 +276,8 @@
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- glOrthof(0, w, h, 0, 0, 1);
+ // put the origin in the left-bottom corner
+ glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
mReadyToRunBarrier.open();
@@ -1791,7 +1792,7 @@
}
GLfloat vtx[8];
- const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+ const GLfloat texCoords[4][2] = { {0,1}, {0,1-v}, {u,1-v}, {u,1} };
glBindTexture(GL_TEXTURE_2D, tname);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1800,6 +1801,22 @@
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vtx);
+ /*
+ * Texture coordinate mapping
+ *
+ * u
+ * 1 +----------+---+
+ * | | | | image is inverted
+ * | V | | w.r.t. the texture
+ * 1-v +----------+ | coordinates
+ * | |
+ * | |
+ * | |
+ * 0 +--------------+
+ * 0 1
+ *
+ */
+
class s_curve_interpolator {
const float nbFrames, s, v;
public:
@@ -1824,10 +1841,10 @@
const GLfloat h = hw_h - (hw_h * v);
const GLfloat x = (hw_w - w) * 0.5f;
const GLfloat y = (hw_h - h) * 0.5f;
- vtx[0] = x; vtx[1] = y + h;
- vtx[2] = x; vtx[3] = y;
- vtx[4] = x + w; vtx[5] = y;
- vtx[6] = x + w; vtx[7] = y + h;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
}
};
@@ -1842,15 +1859,20 @@
const GLfloat h = 1.0f;
const GLfloat x = (hw_w - w) * 0.5f;
const GLfloat y = (hw_h - h) * 0.5f;
- vtx[0] = x; vtx[1] = y + h;
- vtx[2] = x; vtx[3] = y;
- vtx[4] = x + w; vtx[5] = y;
- vtx[6] = x + w; vtx[7] = y + h;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
}
};
// the full animation is 24 frames
- const int nbFrames = 12;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.electron_frames", value, "24");
+ int nbFrames = (atoi(value) + 1) >> 1;
+ if (nbFrames <= 0) // just in case
+ nbFrames = 24;
+
s_curve_interpolator itr(nbFrames, 7.5f);
s_curve_interpolator itg(nbFrames, 8.0f);
s_curve_interpolator itb(nbFrames, 8.5f);
@@ -2225,10 +2247,11 @@
// invert everything, b/c glReadPixel() below will invert the FB
glViewport(0, 0, sw, sh);
glScissor(0, 0, sw, sh);
+ glEnable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
- glOrthof(0, hw_w, 0, hw_h, 0, 1);
+ glOrthof(0, hw_w, hw_h, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
// redraw the screen entirely...
@@ -2244,6 +2267,7 @@
}
// XXX: this is needed on tegra
+ glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, sw, sh);
// check for errors and return screen capture
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 9695344..1f24b58 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -76,8 +76,6 @@
+ "' APN: '" + mApn.apn
+ "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
- setHttpProxy (mApn.proxy, mApn.port);
-
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
@@ -152,38 +150,6 @@
Log.d(LOG_TAG, "[" + getName() + "] " + s);
}
- private void setHttpProxy(String httpProxy, String httpPort) {
-
- if (DBG) log("set http proxy for"
- + "' APN: '" + mActiveApnType
- + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
- if(TextUtils.equals(mActiveApnType, Phone.APN_TYPE_DEFAULT)) {
- if (httpProxy == null || httpProxy.length() == 0) {
- phone.setSystemProperty("net.gprs.http-proxy", null);
- return;
- }
-
- if (httpPort == null || httpPort.length() == 0) {
- httpPort = "8080"; // Default to port 8080
- }
-
- phone.setSystemProperty("net.gprs.http-proxy",
- "http://" + httpProxy + ":" + httpPort + "/");
- } else {
- if (httpProxy == null || httpProxy.length() == 0) {
- phone.setSystemProperty("net.gprs.http-proxy." + mActiveApnType, null);
- return;
- }
-
- if (httpPort == null || httpPort.length() == 0) {
- httpPort = "8080"; // Default to port 8080
- }
-
- phone.setSystemProperty("net.gprs.http-proxy." + mActiveApnType,
- "http://" + httpProxy + ":" + httpPort + "/");
- }
- }
-
private boolean isIpAddress(String address) {
if (address == null) return false;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index fe57d0d..df5898b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1055,10 +1055,16 @@
}
}
if (!found) {
- // ApnContext does not have dcan reorted in data call list.
+ // ApnContext does not have dcac reported in data call list.
+ // Fetch all the ApnContexts that map to this dcac which are in
+ // INITING state too.
if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" +
apnContext.toString() + ")");
- list.add(apnContext);
+ if (apnContext.getDataConnectionAc() != null) {
+ list.addAll(apnContext.getDataConnectionAc().getApnListSync());
+ } else {
+ list.add(apnContext);
+ }
}
}
}
@@ -1110,10 +1116,12 @@
Collection<ApnContext> apns = dcac.getApnListSync();
- // filter out ApnContext with "Connected" state.
+ // filter out ApnContext with "Connected/Connecting" state.
ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
for (ApnContext apnContext : apns) {
- if (apnContext.getState() == State.CONNECTED) {
+ if (apnContext.getState() == State.CONNECTED ||
+ apnContext.getState() == State.CONNECTING ||
+ apnContext.getState() == State.INITING) {
connectedApns.add(apnContext);
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index e1ca756..949589f 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -39,7 +39,10 @@
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
-
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
@@ -57,6 +60,25 @@
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
+ mTextureView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bitmap b = mTextureView.getBitmap(800, 800);
+ BufferedOutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream("/sdcard/out.png"));
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ if (out != null) try {
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
setContentView(mTextureView, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -77,7 +99,7 @@
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- ((View) mTextureView.getParent()).invalidate();
+ mTextureView.invalidate();
}
});
animator.start();
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index c857ded..634e7e3a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -16,7 +16,6 @@
package com.android.test.hwui;
-import android.animation.AnimatorSet;
import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
@@ -34,7 +33,6 @@
private Camera mCamera;
private TextureView mTextureView;
private FrameLayout mContent;
- private AnimatorSet mAnimatorSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -53,7 +51,6 @@
@Override
public void onClick(View v) {
if (mAdded) {
- if (mAnimatorSet != null) mAnimatorSet.cancel();
mContent.removeView(mTextureView);
} else {
mContent.addView(mTextureView);
@@ -62,7 +59,9 @@
}
});
- mContent.addView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ mContent.addView(mTextureView, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER));
mContent.addView(button, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
@@ -72,6 +71,9 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
+ Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
+ mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
+ previewSize.width, previewSize.height, Gravity.CENTER));
try {
mCamera.setPreviewTexture(surface);
@@ -82,20 +84,6 @@
mCamera.startPreview();
mTextureView.setCameraDistance(5000);
-
-// ObjectAnimator rotationY = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
-// rotationY.setRepeatMode(ObjectAnimator.REVERSE);
-// rotationY.setRepeatCount(ObjectAnimator.INFINITE);
-// rotationY.setDuration(4000);
-
-// ObjectAnimator alpha = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f);
-// alpha.setRepeatMode(ObjectAnimator.REVERSE);
-// alpha.setRepeatCount(ObjectAnimator.INFINITE);
-// alpha.setDuration(4000);
-
-// mAnimatorSet = new AnimatorSet();
-// mAnimatorSet.play(alpha).with(rotationY);
-// mAnimatorSet.start();
}
@Override