Merge "aggregating test results when reporting to instrumentation out."
diff --git a/Android.mk b/Android.mk
index d4dc088..352e5eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -150,6 +150,8 @@
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
+ core/java/com/android/internal/policy/IFaceLockCallback.aidl \
+ core/java/com/android/internal/policy/IFaceLockInterface.aidl \
core/java/com/android/internal/os/IDropBoxManagerService.aidl \
core/java/com/android/internal/os/IResultReceiver.aidl \
core/java/com/android/internal/statusbar/IStatusBar.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index e6c4183..c1799a1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -108,6 +108,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IAudioService.P)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index f8b7bd9..804a524 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -190,15 +190,15 @@
field public static final int accountPreferences = 16843423; // 0x101029f
field public static final int accountType = 16843407; // 0x101028f
field public static final int action = 16842797; // 0x101002d
- field public static final int actionBarDivider = 16843689; // 0x10103a9
- field public static final int actionBarItemBackground = 16843690; // 0x10103aa
+ field public static final int actionBarDivider = 16843675; // 0x101039b
+ field public static final int actionBarItemBackground = 16843676; // 0x101039c
field public static final int actionBarSize = 16843499; // 0x10102eb
- field public static final int actionBarSplitStyle = 16843670; // 0x1010396
+ field public static final int actionBarSplitStyle = 16843656; // 0x1010388
field public static final int actionBarStyle = 16843470; // 0x10102ce
field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
field public static final int actionBarTabStyle = 16843507; // 0x10102f3
field public static final int actionBarTabTextStyle = 16843509; // 0x10102f5
- field public static final int actionBarWidgetTheme = 16843685; // 0x10103a5
+ field public static final int actionBarWidgetTheme = 16843671; // 0x1010397
field public static final int actionButtonStyle = 16843480; // 0x10102d8
field public static final int actionDropDownStyle = 16843479; // 0x10102d7
field public static final int actionLayout = 16843515; // 0x10102fb
@@ -211,10 +211,10 @@
field public static final int actionModeCutDrawable = 16843537; // 0x1010311
field public static final int actionModePasteDrawable = 16843539; // 0x1010313
field public static final int actionModeSelectAllDrawable = 16843646; // 0x101037e
- field public static final int actionModeSplitBackground = 16843691; // 0x10103ab
- field public static final int actionModeStyle = 16843682; // 0x10103a2
+ field public static final int actionModeSplitBackground = 16843677; // 0x101039d
+ field public static final int actionModeStyle = 16843668; // 0x1010394
field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
- field public static final int actionProviderClass = 16843671; // 0x1010397
+ field public static final int actionProviderClass = 16843657; // 0x1010389
field public static final int actionViewClass = 16843516; // 0x10102fc
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
@@ -260,8 +260,8 @@
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
- field public static final int backgroundSplit = 16843673; // 0x1010399
- field public static final int backgroundStacked = 16843672; // 0x1010398
+ field public static final int backgroundSplit = 16843659; // 0x101038b
+ field public static final int backgroundStacked = 16843658; // 0x101038a
field public static final int backupAgent = 16843391; // 0x101027f
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -270,7 +270,6 @@
field public static final int borderlessButtonStyle = 16843563; // 0x101032b
field public static final int bottom = 16843184; // 0x10101b0
field public static final int bottomBright = 16842957; // 0x10100cd
- field public static final int bottomChevronDrawable = 16843659; // 0x101038b
field public static final int bottomDark = 16842953; // 0x10100c9
field public static final int bottomLeftRadius = 16843179; // 0x10101ab
field public static final int bottomMedium = 16842958; // 0x10100ce
@@ -318,15 +317,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 = 16843678; // 0x101039e
+ field public static final int colorActivatedHighlight = 16843664; // 0x1010390
field public static final int colorBackground = 16842801; // 0x1010031
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
- field public static final int colorFocusedHighlight = 16843677; // 0x101039d
+ field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
- field public static final int colorLongPressedHighlight = 16843676; // 0x101039c
- field public static final int colorMultiSelectHighlight = 16843679; // 0x101039f
- field public static final int colorPressedHighlight = 16843675; // 0x101039b
+ field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
+ field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
+ field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -370,7 +369,7 @@
field public static final int dialogTitle = 16843250; // 0x10101f2
field public static final int digits = 16843110; // 0x1010166
field public static final int direction = 16843217; // 0x10101d1
- field public static final int directionDescriptions = 16843695; // 0x10103af
+ field public static final int directionDescriptions = 16843681; // 0x10103a1
field public static final int directionPriority = 16843218; // 0x10101d2
field public static final int disableDependentsState = 16843249; // 0x10101f1
field public static final int disabledAlpha = 16842803; // 0x1010033
@@ -384,11 +383,11 @@
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
- field public static final int drawableEnd = 16843681; // 0x10103a1
+ field public static final int drawableEnd = 16843667; // 0x1010393
field public static final int drawableLeft = 16843119; // 0x101016f
field public static final int drawablePadding = 16843121; // 0x1010171
field public static final int drawableRight = 16843120; // 0x1010170
- field public static final int drawableStart = 16843680; // 0x10103a0
+ field public static final int drawableStart = 16843666; // 0x1010392
field public static final int drawableTop = 16843117; // 0x101016d
field public static final int drawingCacheQuality = 16842984; // 0x10100e8
field public static final int dropDownAnchor = 16843363; // 0x1010263
@@ -435,7 +434,7 @@
field public static final int fadeEnabled = 16843390; // 0x101027e
field public static final int fadeOffset = 16843383; // 0x1010277
field public static final int fadeScrollbars = 16843434; // 0x10102aa
- field public static final int fadingEdge = 16842975; // 0x10100df
+ field public static final deprecated int fadingEdge = 16842975; // 0x10100df
field public static final int fadingEdgeLength = 16842976; // 0x10100e0
field public static final int fastScrollAlwaysVisible = 16843573; // 0x1010335
field public static final int fastScrollEnabled = 16843302; // 0x1010226
@@ -445,7 +444,6 @@
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
- field public static final int feedbackCount = 16843665; // 0x1010391
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillEnabled = 16843343; // 0x101024f
@@ -498,7 +496,6 @@
field public static final int hand_hour = 16843011; // 0x1010103
field public static final int hand_minute = 16843012; // 0x1010104
field public static final int handle = 16843354; // 0x101025a
- field public static final int handleDrawable = 16843655; // 0x1010387
field public static final int handleProfiling = 16842786; // 0x1010022
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
field public static final int hardwareAccelerated = 16843475; // 0x10102d3
@@ -507,12 +504,10 @@
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
field public static final int hint = 16843088; // 0x1010150
- field public static final int hitRadius = 16843662; // 0x101038e
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
field public static final int horizontalDivider = 16843053; // 0x101012d
field public static final int horizontalGap = 16843327; // 0x101023f
- field public static final int horizontalOffset = 16843667; // 0x1010393
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
@@ -630,7 +625,6 @@
field public static final int layout_x = 16843135; // 0x101017f
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
- field public static final int leftChevronDrawable = 16843656; // 0x1010388
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -642,8 +636,10 @@
field public static final int listDividerAlertDialog = 16843525; // 0x1010305
field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
field public static final int listPreferredItemHeight = 16842829; // 0x101004d
- field public static final int listPreferredItemHeightLarge = 16843668; // 0x1010394
- field public static final int listPreferredItemHeightSmall = 16843669; // 0x1010395
+ field public static final int listPreferredItemHeightLarge = 16843654; // 0x1010386
+ field public static final int listPreferredItemHeightSmall = 16843655; // 0x1010387
+ field public static final int listPreferredItemPaddingLeft = 16843683; // 0x10103a3
+ field public static final int listPreferredItemPaddingRight = 16843684; // 0x10103a4
field public static final int listSelector = 16843003; // 0x10100fb
field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
field public static final int listViewStyle = 16842868; // 0x1010074
@@ -674,8 +670,8 @@
field public static final int minHeight = 16843072; // 0x1010140
field public static final int minLevel = 16843185; // 0x10101b1
field public static final int minLines = 16843094; // 0x1010156
- field public static final int minResizeHeight = 16843684; // 0x10103a4
- field public static final int minResizeWidth = 16843683; // 0x10103a3
+ field public static final int minResizeHeight = 16843670; // 0x1010396
+ field public static final int minResizeWidth = 16843669; // 0x1010395
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
field public static final int mode = 16843134; // 0x101017e
@@ -705,11 +701,10 @@
field public static final int orderingFromXml = 16843239; // 0x10101e7
field public static final int orientation = 16842948; // 0x10100c4
field public static final int outAnimation = 16843128; // 0x1010178
- field public static final int outerRadius = 16843661; // 0x101038d
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
- field public static final int overridesImplicitlyEnabledSubtype = 16843696; // 0x10103b0
+ field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
@@ -788,6 +783,7 @@
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
field public static final int required = 16843406; // 0x101028e
+ field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeMode = 16843619; // 0x1010363
field public static final int resizeable = 16843405; // 0x101028d
@@ -795,7 +791,6 @@
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
field public static final int right = 16843183; // 0x10101af
- field public static final int rightChevronDrawable = 16843657; // 0x1010389
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
field public static final int rotation = 16843558; // 0x1010326
@@ -871,7 +866,6 @@
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
- field public static final int snapMargin = 16843664; // 0x1010390
field public static final int soundEffectsEnabled = 16843285; // 0x1010215
field public static final int spacing = 16843027; // 0x1010113
field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087
@@ -917,8 +911,8 @@
field public static final int stretchMode = 16843030; // 0x1010116
field public static final int subtitle = 16843473; // 0x10102d1
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
- field public static final int subtypeExtraValue = 16843688; // 0x10103a8
- field public static final int subtypeLocale = 16843687; // 0x10103a7
+ field public static final int subtypeExtraValue = 16843674; // 0x101039a
+ field public static final int subtypeLocale = 16843673; // 0x1010399
field public static final int suggestActionMsg = 16843228; // 0x10101dc
field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
field public static final int summary = 16843241; // 0x10101e9
@@ -940,8 +934,7 @@
field public static final int tag = 16842961; // 0x10100d1
field public static final int targetActivity = 16843266; // 0x1010202
field public static final int targetClass = 16842799; // 0x101002f
- field public static final int targetDescriptions = 16843694; // 0x10103ae
- field public static final int targetDrawables = 16843654; // 0x1010386
+ field public static final int targetDescriptions = 16843680; // 0x10103a0
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
@@ -956,15 +949,15 @@
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 = 16843674; // 0x101039a
+ field public static final int textAllCaps = 16843660; // 0x101038c
field public static final int textAppearance = 16842804; // 0x1010034
field public static final int textAppearanceButton = 16843271; // 0x1010207
field public static final int textAppearanceInverse = 16842805; // 0x1010035
field public static final int textAppearanceLarge = 16842816; // 0x1010040
field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
- field public static final int textAppearanceListItem = 16843692; // 0x10103ac
- field public static final int textAppearanceListItemSmall = 16843693; // 0x10103ad
+ field public static final int textAppearanceListItem = 16843678; // 0x101039e
+ field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
@@ -1033,7 +1026,6 @@
field public static final int toYScale = 16843205; // 0x10101c5
field public static final int top = 16843182; // 0x10101ae
field public static final int topBright = 16842955; // 0x10100cb
- field public static final int topChevronDrawable = 16843658; // 0x101038a
field public static final int topDark = 16842951; // 0x10100c7
field public static final int topLeftRadius = 16843177; // 0x10101a9
field public static final int topOffset = 16843352; // 0x1010258
@@ -1046,7 +1038,7 @@
field public static final int translationY = 16843555; // 0x1010323
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
- field public static final int uiOptions = 16843686; // 0x10103a6
+ field public static final int uiOptions = 16843672; // 0x1010398
field public static final int uncertainGestureColor = 16843382; // 0x1010276
field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
@@ -1065,10 +1057,8 @@
field public static final int verticalCorrection = 16843322; // 0x101023a
field public static final int verticalDivider = 16843054; // 0x101012e
field public static final int verticalGap = 16843328; // 0x1010240
- field public static final int verticalOffset = 16843666; // 0x1010392
field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
field public static final int verticalSpacing = 16843029; // 0x1010115
- field public static final int vibrationDuration = 16843663; // 0x101038f
field public static final int visibility = 16842972; // 0x10100dc
field public static final int visible = 16843156; // 0x1010194
field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1085,7 +1075,6 @@
field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298
field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293
field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294
- field public static final int waveDrawable = 16843660; // 0x101038c
field public static final int webTextViewStyle = 16843449; // 0x10102b9
field public static final int webViewStyle = 16842885; // 0x1010085
field public static final int weekDayTextAppearance = 16843592; // 0x1010348
@@ -2075,7 +2064,8 @@
method public android.accounts.Account[] getAccountsByType(java.lang.String);
method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+ method public deprecated android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+ method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
method public java.lang.String getPassword(android.accounts.Account);
@@ -2104,6 +2094,7 @@
field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
+ field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
field public static final java.lang.String KEY_AUTHTOKEN = "authtoken";
field public static final java.lang.String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
@@ -2452,6 +2443,8 @@
method public abstract void setLogo(android.graphics.drawable.Drawable);
method public abstract void setNavigationMode(int);
method public abstract void setSelectedNavigationItem(int);
+ method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
method public abstract void setSubtitle(java.lang.CharSequence);
method public abstract void setSubtitle(int);
method public abstract void setTitle(java.lang.CharSequence);
@@ -2487,12 +2480,15 @@
public static abstract class ActionBar.Tab {
ctor public ActionBar.Tab();
+ method public abstract java.lang.CharSequence getContentDescription();
method public abstract android.view.View getCustomView();
method public abstract android.graphics.drawable.Drawable getIcon();
method public abstract int getPosition();
method public abstract java.lang.Object getTag();
method public abstract java.lang.CharSequence getText();
method public abstract void select();
+ method public abstract android.app.ActionBar.Tab setContentDescription(int);
+ method public abstract android.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
method public abstract android.app.ActionBar.Tab setCustomView(android.view.View);
method public abstract android.app.ActionBar.Tab setCustomView(int);
method public abstract android.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
@@ -4523,6 +4519,44 @@
field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
}
+ public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
+ method public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method public boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback);
+ method public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+ field public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
+ field public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
+ field public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
+ field public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
+ field public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa
+ field public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb
+ field public static final int SINK_ROLE = 2; // 0x2
+ field public static final int SOURCE_ROLE = 1; // 0x1
+ field public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2
+ field public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1
+ field public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
+ field public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
+ }
+
+ public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDataType();
+ method public java.lang.String getName();
+ method public int getRole();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public abstract class BluetoothHealthCallback {
+ ctor public BluetoothHealthCallback();
+ method public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
+ method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
+ }
+
public abstract interface BluetoothProfile {
method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -6211,6 +6245,7 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
+ field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
@@ -8893,7 +8928,6 @@
method public int getMinimumWidth();
method public abstract int getOpacity();
method public boolean getPadding(android.graphics.Rect);
- method public int getResolvedLayoutDirectionSelf();
method public int[] getState();
method public android.graphics.Region getTransparentRegion();
method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -8928,10 +8962,6 @@
method public abstract void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
}
- public static abstract interface Drawable.Callback2 implements android.graphics.drawable.Drawable.Callback {
- method public abstract int getResolvedLayoutDirection(android.graphics.drawable.Drawable);
- }
-
public static abstract class Drawable.ConstantState {
ctor public Drawable.ConstantState();
method public abstract int getChangingConfigurations();
@@ -9323,6 +9353,7 @@
method public boolean isAutoExposureLockSupported();
method public boolean isAutoWhiteBalanceLockSupported();
method public boolean isSmoothZoomSupported();
+ method public boolean isVideoSnapshotSupported();
method public boolean isZoomSupported();
method public void remove(java.lang.String);
method public void removeGpsData();
@@ -10286,6 +10317,7 @@
method public void playSoundEffect(int);
method public void playSoundEffect(int, float);
method public void registerMediaButtonEventReceiver(android.content.ComponentName);
+ method public void registerRemoteControlClient(android.media.RemoteControlClient);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
method public deprecated void setBluetoothA2dpOn(boolean);
method public void setBluetoothScoOn(boolean);
@@ -10305,6 +10337,7 @@
method public void stopBluetoothSco();
method public void unloadSoundEffects();
method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
+ method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
@@ -10845,6 +10878,40 @@
field public static final int SEEK_FORWARD_AVAILABLE = 3; // 0x3
}
+ public class RemoteControlClient {
+ ctor public RemoteControlClient(android.content.ComponentName);
+ ctor public RemoteControlClient(android.content.ComponentName, android.os.Looper);
+ method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
+ method public void setPlaybackState(int);
+ method public void setTransportControlFlags(int);
+ field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+ field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+ field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+ field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+ field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+ field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+ field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+ field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+ field public static final int PLAYSTATE_BUFFERING = 8; // 0x8
+ field public static final int PLAYSTATE_ERROR = 9; // 0x9
+ field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
+ field public static final int PLAYSTATE_PAUSED = 2; // 0x2
+ field public static final int PLAYSTATE_PLAYING = 3; // 0x3
+ field public static final int PLAYSTATE_REWINDING = 5; // 0x5
+ field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 7; // 0x7
+ field public static final int PLAYSTATE_SKIPPING_FORWARDS = 6; // 0x6
+ field public static final int PLAYSTATE_STOPPED = 1; // 0x1
+ }
+
+ public class RemoteControlClient.MetadataEditor {
+ method public synchronized void apply();
+ method public synchronized void clear();
+ method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+ field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+ }
+
public class Ringtone {
method public int getStreamType();
method public java.lang.String getTitle(android.content.Context);
@@ -16660,6 +16727,7 @@
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_ID = "data_id";
+ field public static final android.net.Uri PROFILE_CONTENT_URI;
}
public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
@@ -16672,6 +16740,7 @@
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 ANY_UNSYNCED = "any_unsynced";
+ field public static final java.lang.String DATA_SET = "data_set";
field public static final java.lang.String SHOULD_SYNC = "should_sync";
field public static final java.lang.String UNGROUPED_COUNT = "summ_count";
field public static final java.lang.String UNGROUPED_VISIBLE = "ungrouped_visible";
@@ -22662,7 +22731,7 @@
method public void recycle();
}
- public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback2 android.view.KeyEvent.Callback {
+ public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
ctor public View(android.content.Context);
ctor public View(android.content.Context, android.util.AttributeSet);
ctor public View(android.content.Context, android.util.AttributeSet, int);
@@ -22679,7 +22748,6 @@
method public void buildDrawingCache();
method public void buildDrawingCache(boolean);
method public void buildLayer();
- method protected boolean canResolveLayoutDirection();
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
method public void cancelLongPress();
@@ -22791,7 +22859,6 @@
method public final android.view.ViewParent getParent();
method public float getPivotX();
method public float getPivotY();
- method public int getResolvedLayoutDirection(android.graphics.drawable.Drawable);
method public android.content.res.Resources getResources();
method public final int getRight();
method protected float getRightFadingEdgeStrength();
@@ -22856,7 +22923,6 @@
method public boolean isHovered();
method public boolean isInEditMode();
method public boolean isInTouchMode();
- method protected static boolean isLayoutDirectionRtl(java.util.Locale);
method public boolean isLayoutRequested();
method public boolean isLongClickable();
method public boolean isOpaque();
@@ -22942,10 +23008,8 @@
method public void requestLayout();
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
- method protected void resetResolvedTextDirection();
method public static int resolveSize(int, int);
method public static int resolveSizeAndState(int, int, int);
- method protected void resolveTextDirection();
method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -23046,7 +23110,6 @@
method public boolean willNotCacheDrawing();
method public boolean willNotDraw();
field public static android.util.Property ALPHA;
- field protected static int DEFAULT_TEXT_DIRECTION;
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -23375,6 +23438,7 @@
method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void requestTransparentRegion(android.view.View);
method protected void resetResolvedLayoutDirection();
+ method protected void resetResolvedTextDirection();
method public void scheduleLayoutAnimation();
method public void setAddStatesFromChildren(boolean);
method public void setAlwaysDrawnWithCacheEnabled(boolean);
@@ -25920,8 +25984,9 @@
ctor public FrameLayout(android.content.Context);
ctor public FrameLayout(android.content.Context, android.util.AttributeSet);
ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int);
- method public boolean getConsiderGoneChildrenWhenMeasuring();
+ method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
method public android.graphics.drawable.Drawable getForeground();
+ method public boolean getMeasureAllChildren();
method protected void onLayout(boolean, int, int, int, int);
method public void setForeground(android.graphics.drawable.Drawable);
method public void setForegroundGravity(int);
@@ -27172,6 +27237,7 @@
method protected void resetResolvedDrawables();
method protected void resetResolvedLayoutDirection();
method protected void resolveDrawables();
+ method protected void resolveTextDirection();
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 2156425..029d107 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -197,6 +197,16 @@
public static final String KEY_CALLER_PID = "callerPid";
/**
+ * The Android package of the caller will be set in the options bundle by the
+ * {@link AccountManager} and will be passed to the AccountManagerService and
+ * to the AccountAuthenticators. The uid of the caller will be known by the
+ * AccountManagerService as well as the AccountAuthenticators so they will be able to
+ * verify that the package is consistent with the uid (a uid might be shared by many
+ * packages).
+ */
+ public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
+
+ /**
* Boolean, if set and 'customTokens' the authenticator is responsible for
* notifications.
* @hide
@@ -880,7 +890,10 @@
* If the account is no longer present on the device, the return value is
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
+ * @deprecated use {@link #getAuthToken(Account, String, android.os.Bundle,
+ * boolean, AccountManagerCallback, android.os.Handler)} instead
*/
+ @Deprecated
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final boolean notifyAuthFailure,
AccountManagerCallback<Bundle> callback, Handler handler) {
@@ -895,6 +908,90 @@
}
/**
+ * Gets an auth token of the specified type for a particular account,
+ * optionally raising a notification if the user must enter credentials.
+ * This method is intended for background tasks and services where the
+ * user should not be immediately interrupted with a password prompt.
+ *
+ * <p>If a previously generated auth token is cached for this account and
+ * type, then it is returned. Otherwise, if a saved password is
+ * available, it is sent to the server to generate a new auth token.
+ * Otherwise, an {@link Intent} is returned which, when started, will
+ * prompt the user for a password. If the notifyAuthFailure parameter is
+ * set, a status bar notification is also created with the same Intent,
+ * alerting the user that they need to enter a password at some point.
+ *
+ * <p>In that case, you may need to wait until the user responds, which
+ * could take hours or days or forever. When the user does respond and
+ * supply a new password, the account manager will broadcast the
+ * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
+ * use to try again.
+ *
+ * <p>If notifyAuthFailure is not set, it is the application's
+ * responsibility to launch the returned Intent at some point.
+ * Either way, the result from this call will not wait for user action.
+ *
+ * <p>Some authenticators have auth token <em>types</em>, whose value
+ * is authenticator-dependent. Some services use different token types to
+ * access different functionality -- for example, Google uses different auth
+ * tokens to access Gmail and Google Calendar for the same account.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param account The account to fetch an auth token for
+ * @param authTokenType The auth token type, an authenticator-dependent
+ * string token, must not be null
+ * @param options Authenticator-specific options for the request,
+ * may be null or empty
+ * @param notifyAuthFailure True to add a notification to prompt the
+ * user for a password if necessary, false to leave that to the caller
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+ * at least the following fields on success:
+ * <ul>
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
+ * </ul>
+ *
+ * (Other authenticator-specific values may be returned.) If the user
+ * must enter credentials, the returned Bundle contains only
+ * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
+ *
+ * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * <ul>
+ * <li> {@link AuthenticatorException} if the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation is canceled for
+ * any reason, incluidng the user canceling a credential request
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * creating a new auth token, usually because of network trouble
+ * </ul>
+ * If the account is no longer present on the device, the return value is
+ * authenticator-dependent. The caller should verify the validity of the
+ * account before requesting an auth token.
+ */
+ public AccountManagerFuture<Bundle> getAuthToken(
+ final Account account, final String authTokenType,
+ final Bundle options, final boolean notifyAuthFailure,
+ AccountManagerCallback<Bundle> callback, Handler handler) {
+ if (account == null) throw new IllegalArgumentException("account is null");
+ if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ return new AmsTask(null, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAuthToken(mResponse, account, authTokenType,
+ notifyAuthFailure, false /* expectActivityLaunch */, options);
+ }
+ }.start();
+ }
+
+ /**
* Asks the user to add an account of a specified type. The authenticator
* for this account type processes this request with the appropriate user
* interface. If the user does elect to create a new account, the account
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 9e2b833..355b1fc 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -793,7 +793,9 @@
* @hide
*/
public void startChangingAnimations() {
- for (Animator anim : currentChangingAnimations.values()) {
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
if (anim instanceof ObjectAnimator) {
((ObjectAnimator) anim).setCurrentPlayTime(0);
}
@@ -802,6 +804,23 @@
}
/**
+ * Ends the animations that are set up for a CHANGING transition. This is a variant of
+ * startChangingAnimations() which is called when the window the transition is playing in
+ * is not visible. We need to make sure the animations put their targets in their end states
+ * and that the transition finishes to remove any mid-process state (such as isRunning()).
+ *
+ * @hide
+ */
+ public void endChangingAnimations() {
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.start();
+ anim.end();
+ }
+ }
+
+ /**
* Returns true if animations are running which animate layout-related properties. This
* essentially means that either CHANGE_APPEARING or CHANGE_DISAPPEARING animations
* are running, since these animations operate on layout-related properties.
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 7acaec8..0d4a067 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -402,13 +402,33 @@
public abstract void setDisplayShowCustomEnabled(boolean showCustom);
/**
- * Set the ActionBar's background.
+ * Set the ActionBar's background. This will be used for the primary
+ * action bar.
*
* @param d Background drawable
+ * @see #setStackedBackgroundDrawable(Drawable)
+ * @see #setSplitBackgroundDrawable(Drawable)
*/
public abstract void setBackgroundDrawable(Drawable d);
/**
+ * Set the ActionBar's stacked background. This will appear
+ * in the second row/stacked bar on some devices and configurations.
+ *
+ * @param d Background drawable for the stacked row
+ */
+ public void setStackedBackgroundDrawable(Drawable d) { }
+
+ /**
+ * Set the ActionBar's split background. This will appear in
+ * the split action bar containing menu-provided action buttons
+ * on some devices and configurations.
+ *
+ * @param d Background drawable for the split bar
+ */
+ public void setSplitBackgroundDrawable(Drawable d) { }
+
+ /**
* @return The current custom view.
*/
public abstract View getCustomView();
@@ -790,6 +810,37 @@
* Select this tab. Only valid if the tab has been added to the action bar.
*/
public abstract void select();
+
+ /**
+ * Set a description of this tab's content for use in accessibility support.
+ * If no content description is provided the title will be used.
+ *
+ * @param resId A resource ID referring to the description text
+ * @return The current instance for call chaining
+ * @see #setContentDescription(CharSequence)
+ * @see #getContentDescription()
+ */
+ public abstract Tab setContentDescription(int resId);
+
+ /**
+ * Set a description of this tab's content for use in accessibility support.
+ * If no content description is provided the title will be used.
+ *
+ * @param contentDesc Description of this tab's content
+ * @return The current instance for call chaining
+ * @see #setContentDescription(int)
+ * @see #getContentDescription()
+ */
+ public abstract Tab setContentDescription(CharSequence contentDesc);
+
+ /**
+ * Gets a brief description of this tab's content for use in accessibility support.
+ *
+ * @return Description of this tab's content
+ * @see #setContentDescription(CharSequence)
+ * @see #setContentDescription(int)
+ */
+ public abstract CharSequence getContentDescription();
}
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 41e3fdf..034e3c7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1638,6 +1638,12 @@
* or later, consider instead using {@link LoaderManager} instead, available
* via {@link #getLoaderManager()}.</em>
*
+ * <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on a cursor obtained using
+ * this method, because the activity will do that for you at the appropriate time. However, if
+ * you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
+ * not</em> automatically close the cursor and, in that case, you must call
+ * {@link Cursor#close()}.</p>
+ *
* @param uri The URI of the content provider to query.
* @param projection List of columns to return.
* @param selection SQL WHERE clause.
@@ -1672,6 +1678,12 @@
* or later, consider instead using {@link LoaderManager} instead, available
* via {@link #getLoaderManager()}.</em>
*
+ * <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on a cursor obtained using
+ * this method, because the activity will do that for you at the appropriate time. However, if
+ * you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
+ * not</em> automatically close the cursor and, in that case, you must call
+ * {@link Cursor#close()}.</p>
+ *
* @param uri The URI of the content provider to query.
* @param projection List of columns to return.
* @param selection SQL WHERE clause.
@@ -1707,6 +1719,12 @@
* or later, consider instead using {@link LoaderManager} instead, available
* via {@link #getLoaderManager()}.</em>
*
+ * <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on cursor obtained from
+ * {@link #managedQuery}, because the activity will do that for you at the appropriate time.
+ * However, if you call {@link #stopManagingCursor} on a cursor from a managed query, the system
+ * <em>will not</em> automatically close the cursor and, in that case, you must call
+ * {@link Cursor#close()}.</p>
+ *
* @param c The Cursor to be managed.
*
* @see #managedQuery(android.net.Uri , String[], String, String[], String)
@@ -1728,6 +1746,10 @@
* {@link #startManagingCursor}, stop the activity's management of that
* cursor.
*
+ * <p><strong>Warning:</strong> After calling this method on a cursor from a managed query,
+ * the system <em>will not</em> automatically close the cursor and you must call
+ * {@link Cursor#close()}.</p>
+ *
* @param c The Cursor that was being managed.
*
* @see #startManagingCursor
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 102fac1..4fe9cef 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1254,6 +1254,12 @@
*/
public ComponentName importanceReasonComponent;
+ /**
+ * When {@link importanceReasonPid} is non-0, this is the importance
+ * of the other pid. @hide
+ */
+ public int importanceReasonImportance;
+
public RunningAppProcessInfo() {
importance = IMPORTANCE_FOREGROUND;
importanceReasonCode = REASON_UNKNOWN;
@@ -1280,6 +1286,7 @@
dest.writeInt(importanceReasonCode);
dest.writeInt(importanceReasonPid);
ComponentName.writeToParcel(importanceReasonComponent, dest);
+ dest.writeInt(importanceReasonImportance);
}
public void readFromParcel(Parcel source) {
@@ -1293,6 +1300,7 @@
importanceReasonCode = source.readInt();
importanceReasonPid = source.readInt();
importanceReasonComponent = ComponentName.readFromParcel(source);
+ importanceReasonImportance = source.readInt();
}
public static final Creator<RunningAppProcessInfo> CREATOR =
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index f1a04f8..7f1f385 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -16,7 +16,10 @@
package android.app;
+import com.android.internal.R;
+
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
@@ -29,8 +32,6 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.internal.R;
-
import java.text.NumberFormat;
/**
@@ -119,6 +120,9 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(mContext);
+ TypedArray a = mContext.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.AlertDialog,
+ com.android.internal.R.attr.alertDialogStyle, 0);
if (mProgressStyle == STYLE_HORIZONTAL) {
/* Use a separate handler to update the text views as they
@@ -149,17 +153,22 @@
}
}
};
- View view = inflater.inflate(R.layout.alert_dialog_progress, null);
+ View view = inflater.inflate(a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_horizontalProgressLayout,
+ R.layout.alert_dialog_progress), null);
mProgress = (ProgressBar) view.findViewById(R.id.progress);
mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
setView(view);
} else {
- View view = inflater.inflate(R.layout.progress_dialog, null);
+ View view = inflater.inflate(a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_progressLayout,
+ R.layout.progress_dialog), null);
mProgress = (ProgressBar) view.findViewById(R.id.progress);
mMessageView = (TextView) view.findViewById(R.id.message);
setView(view);
}
+ a.recycle();
if (mMax > 0) {
setMax(mMax);
}
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 0a01dcf..9b2b8ca 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -32,10 +32,25 @@
* <p>BluetoothHealth is a proxy object for controlling the Bluetooth
* Service via IPC.
*
- * <p> Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHealth proxy object. Use
- * {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
- * @hide
+ * <p> How to connect to a health device which is acting in the source role.
+ * <li> Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothHealth proxy object. </li>
+ * <li> Create an {@link BluetoothHealth} callback and call
+ * {@link #registerSinkAppConfiguration} to register an application
+ * configuration </li>
+ * <li> Pair with the remote device. This currently needs to be done manually
+ * from Bluetooth Settings </li>
+ * <li> Connect to a health device using {@link #connectChannelToSource}. Some
+ * devices will connect the channel automatically. The {@link BluetoothHealth}
+ * callback will inform the application of channel state change. </li>
+ * <li> Use the file descriptor provided with a connected channel to read and
+ * write data to the health channel. </li>
+ * <li> The received data needs to be interpreted using a health manager which
+ * implements the IEEE 11073-xxxxx specifications.
+ * <li> When done, close the health channel by calling {@link #disconnectChannel}
+ * and unregister the application configuration calling
+ * {@link #unregisterAppConfiguration}
+ *
*/
public final class BluetoothHealth implements BluetoothProfile {
private static final String TAG = "BluetoothHealth";
@@ -66,6 +81,20 @@
*/
public static final int CHANNEL_TYPE_ANY = 12;
+ /** @hide */
+ public static final int HEALTH_OPERATION_SUCCESS = 6000;
+ /** @hide */
+ public static final int HEALTH_OPERATION_ERROR = 6001;
+ /** @hide */
+ public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
+ /** @hide */
+ public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
+ /** @hide */
+ public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
+ /** @hide */
+ public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
+
+
/**
* Register an application configuration that acts as a Health SINK.
* This is the configuration that will be used to communicate with health devices
@@ -137,7 +166,6 @@
*
* @param config The health app configuration
* @return Success or failure.
- * @hide
*/
public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
boolean result = false;
@@ -222,16 +250,15 @@
* @param device The remote Bluetooth device.
* @param config The application configuration which has been registered using
* {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
- * @param fd The file descriptor that was associated with the channel.
+ * @param channelId The channel id associated with the channel
* @return If true, the callback associated with the application config will be called.
- * @hide
*/
public boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+ BluetoothHealthAppConfiguration config, int channelId) {
if (mService != null && isEnabled() && isValidDevice(device) &&
config != null) {
try {
- return mService.disconnectChannel(device, config, fd);
+ return mService.disconnectChannel(device, config, channelId);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -248,11 +275,13 @@
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
+ * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
+ * when done.
+ *
* @param device The remote Bluetooth health device
* @param config The application configuration
* @return null on failure, ParcelFileDescriptor on success.
*/
-
public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
if (mService != null && isEnabled() && isValidDevice(device) &&
@@ -300,7 +329,7 @@
}
/**
- * Get connected devices for this specific profile.
+ * Get connected devices for the health profile.
*
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
*
@@ -368,14 +397,15 @@
@Override
public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
int status) {
- mCallback.onHealthAppConfigurationStatusChange(config, status);
+ mCallback.onHealthAppConfigurationStatusChange(config, status);
}
@Override
public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
BluetoothDevice device, int prevState, int newState,
- ParcelFileDescriptor fd) {
- mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd);
+ ParcelFileDescriptor fd, int channelId) {
+ mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
+ channelId);
}
}
@@ -389,13 +419,13 @@
public static final int STATE_CHANNEL_DISCONNECTING = 3;
/** Health App Configuration registration success */
- public static final int APPLICATION_REGISTRATION_SUCCESS = 0;
+ public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
/** Health App Configuration registration failure */
- public static final int APPLICATION_REGISTRATION_FAILURE = 1;
+ public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
/** Health App Configuration un-registration success */
- public static final int APPLICATION_UNREGISTRATION_SUCCESS = 2;
+ public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
/** Health App Configuration un-registration failure */
- public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;
+ public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
private ServiceListener mServiceListener;
private IBluetooth mService;
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 7020249..15a9101 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -26,7 +26,6 @@
* that the Bluetooth Health third party application will register to communicate with the
* remote Bluetooth health device.
*
- * @hide
*/
public final class BluetoothHealthAppConfiguration implements Parcelable {
private final String mName;
@@ -39,6 +38,7 @@
*
* @param name Friendly name associated with the application configuration
* @param dataType Data Type of the remote Bluetooth Health device
+ * @hide
*/
BluetoothHealthAppConfiguration(String name, int dataType) {
mName = name;
@@ -54,6 +54,7 @@
* @param dataType Data Type of the remote Bluetooth Health device
* @param role {@link BluetoothHealth#SOURCE_ROLE} or
* {@link BluetoothHealth#SINK_ROLE}
+ * @hide
*/
BluetoothHealthAppConfiguration(String name, int dataType, int role, int
channelType) {
@@ -93,7 +94,6 @@
mChannelType + "]";
}
- @Override
public int describeContents() {
return 0;
}
@@ -132,6 +132,7 @@
* @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or
* {@link BluetoothHealth#CHANNEL_TYPE_STREAMING} or
* {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
+ * @hide
*/
public int getChannelType() {
return mChannelType;
@@ -155,13 +156,10 @@
}
};
- @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(mName);
out.writeInt(mDataType);
out.writeInt(mRole);
out.writeInt(mChannelType);
}
-
-
}
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
index 0d11bb5..baf2ade 100644
--- a/core/java/android/bluetooth/BluetoothHealthCallback.java
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -21,22 +21,48 @@
import android.util.Log;
/**
- * This class is used for all the {@link BluetoothHealth} callbacks.
- * @hide
+ * This abstract class is used to implement {@link BluetoothHealth} callbacks.
*/
public abstract class BluetoothHealthCallback {
-
private static final String TAG = "BluetoothHealthCallback";
+ /**
+ * Callback to inform change in registration state of the health
+ * application.
+ * <p> This callback is called on the binder thread (not on the UI thread)
+ *
+ * @param config Bluetooth Health app configuration
+ * @param status Success or failure of the registration or unregistration
+ * calls. Can be one of
+ * {@link BluetoothHealth#APP_CONFIG_REGISTRATION_SUCCESS} or
+ * {@link BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
+ * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS} or
+ * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
+ */
public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
- int status) {
- Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + " Status:" + status);
+ int status) {
+ Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
}
+ /**
+ * Callback to inform change in channel state.
+ * <p> Its the responsibility of the implementor of this callback to close the
+ * parcel file descriptor when done. This callback is called on the Binder
+ * thread (not the UI thread)
+ *
+ * @param config The Health app configutation
+ * @param device The Bluetooth Device
+ * @param prevState The previous state of the channel
+ * @param newState The new state of the channel.
+ * @param fd The Parcel File Descriptor when the channel state is connected.
+ * @param channelId The id associated with the channel. This id will be used
+ * in future calls like when disconnecting the channel.
+ */
public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
- BluetoothDevice device, int prevState, int newState,
- ParcelFileDescriptor fd) {
- Log.d(TAG, "onHealthChannelStateChange: " + config + " Device:" + device +
- "PrevState:" + prevState + "NewState:" + newState + "FileDescriptor:" + fd);
+ BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
+ int channelId) {
+ Log.d(TAG, "onHealthChannelStateChange: " + config + "Device: " + device +
+ "prevState:" + prevState + "newState:" + newState + "ParcelFd:" + fd +
+ "ChannelId:" + channelId);
}
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index d4e7f7d..fefeb93 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -116,7 +116,7 @@
boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
int channelType);
- boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, in ParcelFileDescriptor fd);
+ boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, int id);
ParcelFileDescriptor getMainChannelFd(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
List<BluetoothDevice> getConnectedHealthDevices();
List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
diff --git a/core/java/android/bluetooth/IBluetoothHealthCallback.aidl b/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
index 9fe5335..0ace9fe 100644
--- a/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
@@ -27,5 +27,6 @@
{
void onHealthAppConfigurationStatusChange(in BluetoothHealthAppConfiguration config, int status);
void onHealthChannelStateChange(in BluetoothHealthAppConfiguration config,
- in BluetoothDevice device, int prevState, int newState, in ParcelFileDescriptor fd);
+ in BluetoothDevice device, int prevState, int newState, in
+ ParcelFileDescriptor fd, int id);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 46712a9..48f94d0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -239,6 +239,9 @@
* methods of activities and other components are called. Note that you
* <em>must</em> be sure to use {@link #unregisterComponentCallbacks} when
* appropriate in the future; this will not be removed for you.
+ *
+ * @param callback The interface to call. This can be either a
+ * {@link ComponentCallbacks} or {@link ComponentCallbacks2} interface.
*/
public void registerComponentCallbacks(ComponentCallbacks callback) {
getApplicationContext().registerComponentCallbacks(callback);
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index ef6e131..9678d48 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -192,10 +192,10 @@
private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours
/**
- * The amount of time to wait after attempting a bind before canceling a sync and disabling
- * the sync adapter
+ * The amount of time (in milliseconds) to wait after attempting a bind
+ * before canceling a sync and disabling the sync adapter
*/
- public static final long BIND_TIMEOUT_MS = 30 * 1000;
+ public static final long BIND_TIMEOUT_MS = 5 * 60 * 1000;
public void onAccountsUpdated(Account[] accounts) {
// remember if this was the first time this was called after an update
@@ -924,7 +924,7 @@
mStartTime = SystemClock.elapsedRealtime();
mTimeoutStartTime = mStartTime;
mSyncWakeLock = mSyncHandler.getSyncWakeLock(
- mSyncOperation.account.type, mSyncOperation.authority);
+ mSyncOperation.account, mSyncOperation.authority);
mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
mSyncWakeLock.acquire();
}
@@ -1365,7 +1365,7 @@
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
private Long mAlarmScheduleTime = null;
public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
- private final HashMap<Pair<String, String>, PowerManager.WakeLock> mWakeLocks =
+ private final HashMap<Pair<Account, String>, PowerManager.WakeLock> mWakeLocks =
Maps.newHashMap();
private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
@@ -1377,11 +1377,11 @@
}
}
- private PowerManager.WakeLock getSyncWakeLock(String accountType, String authority) {
- final Pair<String, String> wakeLockKey = Pair.create(accountType, authority);
+ private PowerManager.WakeLock getSyncWakeLock(Account account, String authority) {
+ final Pair<Account, String> wakeLockKey = Pair.create(account, authority);
PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
if (wakeLock == null) {
- final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + accountType;
+ final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + account;
wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
wakeLock.setReferenceCounted(false);
mWakeLocks.put(wakeLockKey, wakeLock);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5c641f1..b4e3988 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1021,6 +1021,13 @@
public static final String FEATURE_WIFI = "android.hardware.wifi";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Wi-Fi Direct networking.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 63f2244..58f7869 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -3233,7 +3233,6 @@
* captured pictures.
*
* @return true if video snapshot is supported.
- * @hide
*/
public boolean isVideoSnapshotSupported() {
String str = get(KEY_VIDEO_SNAPSHOT_SUPPORTED);
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 0411b5c..784bcc5 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -154,16 +154,16 @@
* All values are in micro-Tesla (uT) and measure the ambient magnetic field
* in the X, Y and Z axis.
*
- * <h4>{@link android.hardware.Sensor#TYPE_GYROSCOPE Sensor.TYPE_GYROSCOPE}:</h4>
- * All values are in radians/second and measure the rate of rotation
- * around the X, Y and Z axis. The coordinate system is the same as is
- * used for the acceleration sensor. Rotation is positive in the counter-clockwise
- * direction. That is, an observer looking from some positive location on the x, y.
- * or z axis at a device positioned on the origin would report positive rotation
- * if the device appeared to be rotating counter clockwise. Note that this is the
- * standard mathematical definition of positive rotation and does not agree with the
- * definition of roll given earlier.
- *
+ * <h4>{@link android.hardware.Sensor#TYPE_GYROSCOPE Sensor.TYPE_GYROSCOPE}:
+ * </h4> All values are in radians/second and measure the rate of rotation
+ * around the device's local X, Y and Z axis. The coordinate system is the
+ * same as is used for the acceleration sensor. Rotation is positive in the
+ * counter-clockwise direction. That is, an observer looking from some
+ * positive location on the x, y or z axis at a device positioned on the
+ * origin would report positive rotation if the device appeared to be
+ * rotating counter clockwise. Note that this is the standard mathematical
+ * definition of positive rotation and does not agree with the definition of
+ * roll given earlier.
* <ul>
* <p>
* values[0]: Angular speed around the x-axis
@@ -176,28 +176,61 @@
* </p>
* </ul>
* <p>
- * Typically the output of the gyroscope is integrated over time to calculate
- * an angle, for example:
+ * Typically the output of the gyroscope is integrated over time to
+ * calculate a rotation describing the change of angles over the timestep,
+ * for example:
* </p>
+ *
* <pre class="prettyprint">
* private static final float NS2S = 1.0f / 1000000000.0f;
+ * private final float[] deltaRotationVector = new float[4]();
* private float timestamp;
- * public void onSensorChanged(SensorEvent event)
- * {
+ *
+ * public void onSensorChanged(SensorEvent event) {
+ * // This timestep's delta rotation to be multiplied by the current rotation
+ * // after computing it from the gyro sample data.
* if (timestamp != 0) {
* final float dT = (event.timestamp - timestamp) * NS2S;
- * angle[0] += event.values[0] * dT;
- * angle[1] += event.values[1] * dT;
- * angle[2] += event.values[2] * dT;
+ * // Axis of the rotation sample, not normalized yet.
+ * float axisX = event.values[0];
+ * float axisY = event.values[1];
+ * float axisZ = event.values[2];
+ *
+ * // Calculate the angular speed of the sample
+ * float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
+ *
+ * // Normalize the rotation vector if it's big enough to get the axis
+ * if (omegaMagnitude > EPSILON) {
+ * axisX /= omegaMagnitude;
+ * axisY /= omegaMagnitude;
+ * axisZ /= omegaMagnitude;
+ * }
+ *
+ * // Integrate around this axis with the angular speed by the timestep
+ * // in order to get a delta rotation from this sample over the timestep
+ * // We will convert this axis-angle representation of the delta rotation
+ * // into a quaternion before turning it into the rotation matrix.
+ * float thetaOverTwo = omegaMagnitude * dT / 2.0f;
+ * float sinThetaOverTwo = sin(thetaOverTwo);
+ * float cosThetaOverTwo = cos(thetaOverTwo);
+ * deltaRotationVector[0] = sinThetaOverTwo * axisX;
+ * deltaRotationVector[1] = sinThetaOverTwo * axisY;
+ * deltaRotationVector[2] = sinThetaOverTwo * axisZ;
+ * deltaRotationVector[3] = cosThetaOverTwo;
* }
* timestamp = event.timestamp;
+ * float[] deltaRotationMatrix = new float[9];
+ * SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
+ * // User code should concatenate the delta rotation we computed with the current rotation
+ * // in order to get the updated rotation.
+ * // rotationCurrent = rotationCurrent * deltaRotationMatrix;
* }
* </pre>
- *
- * <p>In practice, the gyroscope noise and offset will introduce some errors which need
- * to be compensated for. This is usually done using the information from other
- * sensors, but is beyond the scope of this document.</p>
- *
+ * <p>
+ * In practice, the gyroscope noise and offset will introduce some errors
+ * which need to be compensated for. This is usually done using the
+ * information from other sensors, but is beyond the scope of this document.
+ * </p>
* <h4>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:</h4>
* <ul>
* <p>
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 44e7e52..4fc63ed 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
/***
@@ -142,4 +143,17 @@
@Override public boolean hasFocus() {
return this.isEnabled();
}
+
+ /**
+ * @hide
+ */
+ @Override protected void viewClicked(InputMethodManager imm) {
+ // As an instance of this class is supposed to be owned by IMS,
+ // and it has a reference to the IMS (the current IME),
+ // we just need to call back its onViewClicked() here.
+ // It should be good to avoid unnecessary IPCs by doing this as well.
+ if (mIME != null) {
+ mIME.onViewClicked(false);
+ }
+ }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 370e22a..7d3cd92 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -618,7 +618,7 @@
mTheme = Resources.selectSystemTheme(mTheme,
getApplicationInfo().targetSdkVersion,
android.R.style.Theme_InputMethod,
- android.R.style.Theme_Holo,
+ android.R.style.Theme_Holo_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod);
super.setTheme(mTheme);
super.onCreate();
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 88abf1a..65c1bd5 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -195,6 +195,8 @@
intent.getStringExtra(Phone.STATE_KEY));
String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+ mNetworkInfo.setRoaming(intent.getBooleanExtra(Phone.DATA_NETWORK_ROAMING_KEY,
+ false));
mNetworkInfo.setIsAvailable(!intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY,
false));
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 3918cfd..f3be39c 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -102,6 +102,21 @@
this.txPackets = txPackets;
this.operations = operations;
}
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("iface=").append(iface);
+ builder.append(" uid=").append(uid);
+ builder.append(" set=").append(setToString(set));
+ builder.append(" tag=").append(tagToString(tag));
+ builder.append(" rxBytes=").append(rxBytes);
+ builder.append(" rxPackets=").append(rxPackets);
+ builder.append(" txBytes=").append(txBytes);
+ builder.append(" txPackets=").append(txPackets);
+ builder.append(" operations=").append(operations);
+ return builder.toString();
+ }
}
public NetworkStats(long elapsedRealtime, int initialSize) {
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 9302060..e0130b5 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -36,7 +36,7 @@
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends Binder implements IMountService {
private static class Proxy implements IMountService {
- private IBinder mRemote;
+ private final IBinder mRemote;
Proxy(IBinder remote) {
mRemote = remote;
@@ -589,6 +589,22 @@
return _result;
}
+ public int getEncryptionState() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_getEncryptionState, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
public int decryptStorage(String password) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -741,6 +757,8 @@
static final int TRANSACTION_getSecureContainerFilesystemPath = IBinder.FIRST_CALL_TRANSACTION + 30;
+ static final int TRANSACTION_getEncryptionState = IBinder.FIRST_CALL_TRANSACTION + 31;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1062,6 +1080,13 @@
reply.writeString(path);
return true;
}
+ case TRANSACTION_getEncryptionState: {
+ data.enforceInterface(DESCRIPTOR);
+ int result = getEncryptionState();
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1222,6 +1247,21 @@
*/
public boolean isExternalStorageEmulated() throws RemoteException;
+ /** The volume is not encrypted. */
+ static final int ENCRYPTION_STATE_NONE = 1;
+ /** The volume has been encrypted succesfully. */
+ static final int ENCRYPTION_STATE_OK = 0;
+ /** The volume is in a bad state. */
+ static final int ENCRYPTION_STATE_ERROR_UNKNOWN = -1;
+ /** The volume is in a bad state - partially encrypted. Data is likely irrecoverable. */
+ static final int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2;
+
+ /**
+ * Determines the encryption state of the volume.
+ * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible values.
+ */
+ public int getEncryptionState() throws RemoteException;
+
/**
* Decrypts any encrypted volumes.
*/
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1f2b342..ca1d0d9 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -34,6 +34,7 @@
import android.database.DatabaseUtils;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.DisplayMetrics;
@@ -44,6 +45,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* <p>
@@ -167,6 +171,22 @@
public static final String STREQUENT_PHONE_ONLY = "strequent_phone_only";
/**
+ * A key to a boolean in the "extras" bundle of the cursor.
+ * The boolean indicates that the provider did not create a snippet and that the client asking
+ * for the snippet should do it (true means the snippeting was deferred to the client).
+ *
+ * @hide
+ */
+ public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
+
+ /**
+ * Key to retrieve the original query on the client side.
+ *
+ * @hide
+ */
+ public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
+
+ /**
* @hide
*/
public static final class Preferences {
@@ -4357,6 +4377,12 @@
Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities");
/**
+ * The content:// style URI for this table, specific to the user's profile.
+ */
+ public static final Uri PROFILE_CONTENT_URI =
+ Uri.withAppendedPath(Profile.CONTENT_URI, "raw_contact_entities");
+
+ /**
* The MIME type of {@link #CONTENT_URI} providing a directory of raw contact entities.
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
@@ -4857,6 +4883,19 @@
* @hide
*/
public static final String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
+
+ /**
+ * A key to ask the provider to defer the snippeting to the client if possible.
+ * Value of 1 implies true, 0 implies false when 0 is the default.
+ * When a cursor is returned to the client, it should check for an extra with the name
+ * {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
+ * should do its own snippeting using {@link ContactsContract#snippetize}. If
+ * it doesn't exist, the snippet column in the cursor should already contain a snippetized
+ * string.
+ *
+ * @hide
+ */
+ public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
}
/**
@@ -7053,6 +7092,18 @@
public static final String ACCOUNT_TYPE = "account_type";
/**
+ * The data set within the account that this row belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' data.
+ *
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DATA_SET = "data_set";
+
+ /**
* Depending on the mode defined by the sync-adapter, this flag controls
* the top-level sync behavior for this data source.
* <p>
@@ -8054,4 +8105,138 @@
public static final String DATA_SET = "com.android.contacts.extra.DATA_SET";
}
}
+
+ /**
+ * Creates a snippet out of the given content that matches the given query.
+ * @param content - The content to use to compute the snippet.
+ * @param displayName - Display name for the contact - if this already contains the search
+ * content, no snippet should be shown.
+ * @param query - String to search for in the content.
+ * @param snippetStartMatch - Marks the start of the matching string in the snippet.
+ * @param snippetEndMatch - Marks the end of the matching string in the snippet.
+ * @param snippetEllipsis - Ellipsis string appended to the end of the snippet (if too long).
+ * @param snippetMaxTokens - Maximum number of words from the snippet that will be displayed.
+ * @return The computed snippet, or null if the snippet could not be computed or should not be
+ * shown.
+ *
+ * @hide
+ */
+ public static String snippetize(String content, String displayName, String query,
+ char snippetStartMatch, char snippetEndMatch, String snippetEllipsis,
+ int snippetMaxTokens) {
+
+ String lowerQuery = query != null ? query.toLowerCase() : null;
+ if (TextUtils.isEmpty(content) || TextUtils.isEmpty(query) ||
+ TextUtils.isEmpty(displayName) || !content.toLowerCase().contains(lowerQuery)) {
+ return null;
+ }
+
+ // If the display name already contains the query term, return empty - snippets should
+ // not be needed in that case.
+ String lowerDisplayName = displayName != null ? displayName.toLowerCase() : "";
+ List<String> nameTokens = new ArrayList<String>();
+ List<Integer> nameTokenOffsets = new ArrayList<Integer>();
+ split(lowerDisplayName.trim(), nameTokens, nameTokenOffsets);
+ for (String nameToken : nameTokens) {
+ if (nameToken.startsWith(lowerQuery)) {
+ return null;
+ }
+ }
+
+ String[] contentLines = content.split("\n");
+
+ // Locate the lines of the content that contain the query term.
+ for (String contentLine : contentLines) {
+ if (contentLine.toLowerCase().contains(lowerQuery)) {
+
+ // Line contains the query string - now search for it at the start of tokens.
+ List<String> lineTokens = new ArrayList<String>();
+ List<Integer> tokenOffsets = new ArrayList<Integer>();
+ split(contentLine.trim(), lineTokens, tokenOffsets);
+
+ // As we find matches against the query, we'll populate this list with the marked
+ // (or unchanged) tokens.
+ List<String> markedTokens = new ArrayList<String>();
+
+ int firstToken = -1;
+ int lastToken = -1;
+ for (int i = 0; i < lineTokens.size(); i++) {
+ String token = lineTokens.get(i);
+ String lowerToken = token.toLowerCase();
+ if (lowerToken.startsWith(lowerQuery)) {
+
+ // Query term matched; surround the token with match markers.
+ markedTokens.add(snippetStartMatch + token + snippetEndMatch);
+
+ // If this is the first token found with a match, mark the token
+ // positions to use for assembling the snippet.
+ if (firstToken == -1) {
+ firstToken =
+ Math.max(0, i - (int) Math.floor(
+ Math.abs(snippetMaxTokens)
+ / 2.0));
+ lastToken =
+ Math.min(lineTokens.size(), firstToken +
+ Math.abs(snippetMaxTokens));
+ }
+ } else {
+ markedTokens.add(token);
+ }
+ }
+
+ // Assemble the snippet by piecing the tokens back together.
+ if (firstToken > -1) {
+ StringBuilder sb = new StringBuilder();
+ if (firstToken > 0) {
+ sb.append(snippetEllipsis);
+ }
+ for (int i = firstToken; i < lastToken; i++) {
+ String markedToken = markedTokens.get(i);
+ String originalToken = lineTokens.get(i);
+ sb.append(markedToken);
+ if (i < lastToken - 1) {
+ // Add the characters that appeared between this token and the next.
+ sb.append(contentLine.substring(
+ tokenOffsets.get(i) + originalToken.length(),
+ tokenOffsets.get(i + 1)));
+ }
+ }
+ if (lastToken < lineTokens.size()) {
+ sb.append(snippetEllipsis);
+ }
+ return sb.toString();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Pattern for splitting a line into tokens. This matches e-mail addresses as a single token,
+ * otherwise splitting on any group of non-alphanumeric characters.
+ *
+ * @hide
+ */
+ private static Pattern SPLIT_PATTERN =
+ Pattern.compile("([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
+
+ /**
+ * Helper method for splitting a string into tokens. The lists passed in are populated with the
+ * tokens and offsets into the content of each token. The tokenization function parses e-mail
+ * addresses as a single token; otherwise it splits on any non-alphanumeric character.
+ * @param content Content to split.
+ * @param tokens List of token strings to populate.
+ * @param offsets List of offsets into the content for each token returned.
+ *
+ * @hide
+ */
+ private static void split(String content, List<String> tokens, List<Integer> offsets) {
+ Matcher matcher = SPLIT_PATTERN.matcher(content);
+ while (matcher.find()) {
+ tokens.add(matcher.group());
+ offsets.add(matcher.start());
+ }
+ }
+
+
}
diff --git a/core/java/android/provider/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java
index e8177ca..f1189e4 100644
--- a/core/java/android/provider/SyncStateContract.java
+++ b/core/java/android/provider/SyncStateContract.java
@@ -74,6 +74,12 @@
Account account) throws RemoteException {
Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
new String[]{account.name, account.type}, null);
+
+ // Unable to query the provider
+ if (c == null) {
+ throw new RemoteException();
+ }
+
try {
if (c.moveToNext()) {
return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA));
@@ -123,6 +129,11 @@
Account account) throws RemoteException {
Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
new String[]{account.name, account.type}, null);
+
+ if (c == null) {
+ throw new RemoteException();
+ }
+
try {
if (c.moveToNext()) {
long rowId = c.getLong(1);
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index 69fbca3..ac46ee2 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -109,6 +109,8 @@
private static final int DEVICES_DISCONNECT_TIMEOUT = 104;
// Prepare Bluetooth timeout happens
private static final int PREPARE_BLUETOOTH_TIMEOUT = 105;
+ // Bluetooth Powerdown timeout happens
+ private static final int POWER_DOWN_TIMEOUT = 106;
private Context mContext;
private BluetoothService mBluetoothService;
@@ -129,6 +131,8 @@
private static final int PREPARE_BLUETOOTH_TIMEOUT_TIME = 10000;
+ private static final int POWER_DOWN_TIMEOUT_TIME = 5000;
+
BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
BluetoothAdapter bluetoothAdapter) {
super(TAG);
@@ -386,6 +390,11 @@
break;
case USER_TURN_OFF: // ignore
break;
+ case POWER_STATE_CHANGED:
+ if ((Boolean) message.obj) {
+ recoverStateMachine(TURN_HOT, null);
+ }
+ break;
default:
return NOT_HANDLED;
}
@@ -420,14 +429,27 @@
}
break;
case POWER_STATE_CHANGED:
+ removeMessages(POWER_DOWN_TIMEOUT);
if (!((Boolean) message.obj)) {
- transitionTo(mHotOff);
- finishSwitchingOff();
+ if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {
+ transitionTo(mHotOff);
+ finishSwitchingOff();
+ }
+ } else {
+ if (mPublicState != BluetoothAdapter.STATE_TURNING_ON) {
+ if (mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+ recoverStateMachine(TURN_HOT, null);
+ } else {
+ recoverStateMachine(TURN_COLD, null);
+ }
+ }
}
break;
case ALL_DEVICES_DISCONNECTED:
removeMessages(DEVICES_DISCONNECT_TIMEOUT);
mBluetoothService.switchConnectable(false);
+ sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
break;
case DEVICES_DISCONNECT_TIMEOUT:
sendMessage(ALL_DEVICES_DISCONNECTED);
@@ -439,6 +461,17 @@
deferMessage(obtainMessage(TURN_HOT));
}
break;
+ case POWER_DOWN_TIMEOUT:
+ transitionTo(mHotOff);
+ finishSwitchingOff();
+ // reset the hardware for error recovery
+ Log.e(TAG, "Devices failed to power down, reseting...");
+ deferMessage(obtainMessage(TURN_COLD));
+ if (mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+ deferMessage(obtainMessage(TURN_HOT));
+ }
+ break;
case USER_TURN_ON:
case AIRPLANE_MODE_OFF:
case AIRPLANE_MODE_ON:
@@ -501,6 +534,7 @@
DEVICES_DISCONNECT_TIMEOUT_TIME);
} else {
mBluetoothService.switchConnectable(false);
+ sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
}
// we turn all the way to PowerOff with AIRPLANE_MODE_ON
@@ -520,6 +554,12 @@
case PER_PROCESS_TURN_OFF:
perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
break;
+ case POWER_STATE_CHANGED:
+ if ((Boolean) message.obj) {
+ // reset the state machine and send it TURN_ON_CONTINUE message
+ recoverStateMachine(USER_TURN_ON, false);
+ }
+ break;
default:
return NOT_HANDLED;
}
@@ -540,7 +580,7 @@
if (what == PER_PROCESS_TURN_ON) {
isTurningOn = true;
- } else if (what == PER_PROCESS_TURN_OFF) {
+ } else if (what == USER_TURN_OFF) {
isTurningOn = false;
} else {
Log.e(TAG, "enter PerProcessState: wrong msg: " + what);
@@ -568,12 +608,31 @@
}
break;
case POWER_STATE_CHANGED:
+ removeMessages(POWER_DOWN_TIMEOUT);
if (!((Boolean) message.obj)) {
transitionTo(mHotOff);
if (!mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
deferMessage(obtainMessage(TURN_COLD));
}
+ } else {
+ if (!isTurningOn) {
+ recoverStateMachine(TURN_COLD, null);
+ for (IBluetoothStateChangeCallback c:
+ mBluetoothService.getApplicationStateChangeCallbacks()) {
+ perProcessCallback(false, c);
+ deferMessage(obtainMessage(PER_PROCESS_TURN_ON, c));
+ }
+ }
+ }
+ break;
+ case POWER_DOWN_TIMEOUT:
+ transitionTo(mHotOff);
+ Log.e(TAG, "Power-down timed out, resetting...");
+ deferMessage(obtainMessage(TURN_COLD));
+ if (mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+ deferMessage(obtainMessage(TURN_HOT));
}
break;
case USER_TURN_ON:
@@ -616,10 +675,12 @@
perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
mBluetoothService.switchConnectable(false);
+ sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
}
break;
case AIRPLANE_MODE_ON:
mBluetoothService.switchConnectable(false);
+ sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
allProcessesCallback(false);
// we turn all the way to PowerOff with AIRPLANE_MODE_ON
deferMessage(obtainMessage(AIRPLANE_MODE_ON));
@@ -699,6 +760,17 @@
mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
}
+ /**
+ * bluetoothd has crashed and recovered, the adapter state machine has to
+ * reset itself and try to return to previous state
+ */
+ private void recoverStateMachine(int what, Object obj) {
+ Log.e(TAG, "Get unexpected power on event, reset with: " + what);
+ transitionTo(mHotOff);
+ deferMessage(obtainMessage(TURN_COLD));
+ deferMessage(obtainMessage(what, obj));
+ }
+
private void dump(PrintWriter pw) {
IState currentState = getCurrentState();
if (currentState == mPowerOff) {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 6eff796..56da69d 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -20,6 +20,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHealth;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
@@ -59,9 +60,8 @@
// from remote device when Android is in Suspend state.
private PowerManager.WakeLock mWakeLock;
- private static final int EVENT_RESTART_BLUETOOTH = 1;
- private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
- private static final int EVENT_AGENT_CANCEL = 3;
+ private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 1;
+ private static final int EVENT_AGENT_CANCEL = 2;
private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
private static final int CREATE_DEVICE_SUCCESS = 0;
@@ -75,9 +75,6 @@
public void handleMessage(Message msg) {
String address = null;
switch (msg.what) {
- case EVENT_RESTART_BLUETOOTH:
- mBluetoothService.restart();
- break;
case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
address = (String)msg.obj;
if (address != null) {
@@ -375,9 +372,6 @@
} else if (name.equals("Powered")) {
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,
propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));
- // bluetoothd has restarted, re-read all our properties.
- // Note: bluez only sends this property change when it restarts.
- onRestartRequired();
} else if (name.equals("DiscoverableTimeout")) {
adapterProperties.setProperty(name, propValues[1]);
}
@@ -981,6 +975,22 @@
}
/**
+ * Called by native code for the async response to a Connect
+ * method call to org.bluez.Health
+ *
+ * @param chanCode The internal id of the channel
+ * @param result Result code of the operation.
+ */
+ private void onHealthDeviceConnectionResult(int chanCode, int result) {
+ log ("onHealthDeviceConnectionResult " + chanCode + " " + result);
+ // Success case gets handled by Property Change signal
+ if (result != BluetoothHealth.HEALTH_OPERATION_SUCCESS) {
+ mBluetoothService.onHealthDeviceChannelConnectionError(chanCode,
+ BluetoothHealth.STATE_CHANNEL_DISCONNECTED);
+ }
+ }
+
+ /**
* Called by native code on a DeviceDisconnected signal from
* org.bluez.NetworkServer.
*
@@ -1033,14 +1043,6 @@
mBluetoothService.onHealthDeviceChannelChanged(devicePath, channelPath, exists);
}
- private void onRestartRequired() {
- if (mBluetoothService.isEnabled()) {
- Log.e(TAG, "*** A serious error occurred (did bluetoothd crash?) - " +
- "restarting Bluetooth ***");
- mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
- }
- }
-
private static void log(String msg) {
Log.d(TAG, msg);
}
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 51c995e..2d80de4 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -29,6 +29,8 @@
import android.os.RemoteException;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -47,7 +49,6 @@
private static final boolean DBG = true;
private static BluetoothHealthProfileHandler sInstance;
- private Context mContext;
private BluetoothService mBluetoothService;
private ArrayList<HealthChannel> mHealthChannels;
private HashMap <BluetoothHealthAppConfiguration, String> mHealthAppConfigs;
@@ -76,6 +77,16 @@
mConfig = config;
mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
}
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mChannelPath == null ? 0 : mChannelPath.hashCode());
+ result = 31 * result + mDevice.hashCode();
+ result = 31 * result + mConfig.hashCode();
+ result = 31 * result + mChannelType;
+ return result;
+ }
}
private final Handler mHandler = new Handler() {
@@ -98,28 +109,38 @@
}
if (path == null) {
- mCallbacks.remove(registerApp);
callHealthApplicationStatusCallback(registerApp,
- BluetoothHealth.APPLICATION_REGISTRATION_FAILURE);
+ BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE);
+ mCallbacks.remove(registerApp);
} else {
mHealthAppConfigs.put(registerApp, path);
callHealthApplicationStatusCallback(registerApp,
- BluetoothHealth.APPLICATION_REGISTRATION_SUCCESS);
+ BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS);
}
break;
case MESSAGE_UNREGISTER_APPLICATION:
BluetoothHealthAppConfiguration unregisterApp =
(BluetoothHealthAppConfiguration) msg.obj;
+
+ // Disconnect all the channels
+ for (HealthChannel chan : mHealthChannels) {
+ if (chan.mConfig.equals(unregisterApp) &&
+ chan.mState != BluetoothHealth.STATE_CHANNEL_DISCONNECTED) {
+ disconnectChannel(chan.mDevice, unregisterApp, chan.hashCode());
+ }
+ }
+
boolean result = mBluetoothService.unregisterHealthApplicationNative(
mHealthAppConfigs.get(unregisterApp));
if (result) {
- mCallbacks.remove(unregisterApp);
callHealthApplicationStatusCallback(unregisterApp,
- BluetoothHealth.APPLICATION_UNREGISTRATION_SUCCESS);
+ BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS);
+ mCallbacks.remove(unregisterApp);
+ mHealthAppConfigs.remove(unregisterApp);
} else {
callHealthApplicationStatusCallback(unregisterApp,
- BluetoothHealth.APPLICATION_UNREGISTRATION_FAILURE);
+ BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE);
}
break;
case MESSAGE_CONNECT_CHANNEL:
@@ -130,10 +151,11 @@
String channelType = getStringChannelType(chan.mChannelType);
if (!mBluetoothService.createChannelNative(deviceObjectPath, configPath,
- channelType)) {
+ channelType, chan.hashCode())) {
int prevState = chan.mState;
int state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
- callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null);
+ callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null,
+ chan.hashCode());
mHealthChannels.remove(chan);
}
}
@@ -141,7 +163,6 @@
};
private BluetoothHealthProfileHandler(Context context, BluetoothService service) {
- mContext = context;
mBluetoothService = service;
mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
mHealthChannels = new ArrayList<HealthChannel>();
@@ -205,7 +226,7 @@
int prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
int state = BluetoothHealth.STATE_CHANNEL_CONNECTING;
- callHealthChannelCallback(config, device, prevState, state, null);
+ callHealthChannelCallback(config, device, prevState, state, null, chan.hashCode());
Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_CHANNEL);
msg.obj = chan;
@@ -235,37 +256,44 @@
}
boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
- HealthChannel chan = findChannelByFd(device, config, fd);
- if (chan == null) return false;
+ BluetoothHealthAppConfiguration config, int id) {
+ HealthChannel chan = findChannelById(id);
+ if (chan == null) {
+ return false;
+ }
String deviceObjectPath =
mBluetoothService.getObjectPathFromAddress(device.getAddress());
- if (mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath)) {
- int prevState = chan.mState;
- chan.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTING;
+
+ mBluetoothService.releaseChannelFdNative(chan.mChannelPath);
+
+ int prevState = chan.mState;
+ chan.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTING;
+ callHealthChannelCallback(config, device, prevState, chan.mState,
+ null, chan.hashCode());
+
+ if (!mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath,
+ chan.hashCode())) {
+ prevState = chan.mState;
+ chan.mState = BluetoothHealth.STATE_CHANNEL_CONNECTED;
callHealthChannelCallback(config, device, prevState, chan.mState,
- chan.mChannelFd);
- return true;
- } else {
+ chan.mChannelFd, chan.hashCode());
return false;
+ } else {
+ return true;
}
}
- private HealthChannel findChannelByFd(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+ private HealthChannel findChannelById(int id) {
for (HealthChannel chan : mHealthChannels) {
- if (chan.mChannelFd.equals(fd) && chan.mDevice.equals(device) &&
- chan.mConfig.equals(config)) return chan;
+ if (chan.hashCode() == id) return chan;
}
return null;
}
- private HealthChannel findChannelByPath(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, String path) {
+ private HealthChannel findChannelByPath(BluetoothDevice device, String path) {
for (HealthChannel chan : mHealthChannels) {
- if (chan.mChannelPath.equals(path) && chan.mDevice.equals(device) &&
- chan.mConfig.equals(config)) return chan;
+ if (path.equals(chan.mChannelPath) && device.equals(chan.mDevice)) return chan;
}
return null;
}
@@ -296,7 +324,15 @@
ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
HealthChannel chan = getMainChannel(device, config);
- if (chan != null) return chan.mChannelFd;
+ if (chan != null) {
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = chan.mChannelFd.dup();
+ return pfd;
+ } catch (IOException e) {
+ return null;
+ }
+ }
String objectPath =
mBluetoothService.getObjectPathFromAddress(device.getAddress());
@@ -308,14 +344,18 @@
// We had no record of the main channel but querying Bluez we got a
// main channel. We might not have received the PropertyChanged yet for
// the main channel creation so update our data structure here.
- chan = findChannelByPath(device, config, mainChannelPath);
+ chan = findChannelByPath(device, mainChannelPath);
if (chan == null) {
errorLog("Main Channel present but we don't have any account of it:" +
device +":" + config);
return null;
}
chan.mMainChannel = true;
- return chan.mChannelFd;
+ try {
+ return chan.mChannelFd.dup();
+ } catch (IOException e) {
+ return null;
+ }
}
/*package*/ void onHealthDevicePropertyChanged(String devicePath,
@@ -334,7 +374,7 @@
BluetoothHealthAppConfiguration config = findHealthApplication(device,
channelPath);
if (config != null) {
- HealthChannel chan = findChannelByPath(device, config, channelPath);
+ HealthChannel chan = findChannelByPath(device, channelPath);
if (chan == null) {
errorLog("Health Channel is not present:" + channelPath);
} else {
@@ -343,24 +383,34 @@
}
}
+ /*package*/ void onHealthDeviceChannelConnectionError(int chanCode,
+ int state) {
+ HealthChannel channel = findChannelById(chanCode);
+ if (channel == null) errorLog("No record of this channel:" + chanCode);
+
+ callHealthChannelCallback(channel.mConfig, channel.mDevice, channel.mState, state, null,
+ chanCode);
+ }
+
private BluetoothHealthAppConfiguration findHealthApplication(
BluetoothDevice device, String channelPath) {
BluetoothHealthAppConfiguration config = null;
- String configPath = mBluetoothService.getChannelApplicationNative(channelPath);
+ HealthChannel chan = findChannelByPath(device, channelPath);
- if (configPath == null) {
- errorLog("No associated application for Health Channel:" + channelPath);
- return null;
+ if (chan != null) {
+ config = chan.mConfig;
} else {
- for (Entry<BluetoothHealthAppConfiguration, String> e :
- mHealthAppConfigs.entrySet()) {
- if (e.getValue().equals(configPath)) {
- config = e.getKey();
+ String configPath = mBluetoothService.getChannelApplicationNative(channelPath);
+ if (configPath == null) {
+ errorLog("Config path is null for application");
+ } else {
+ for (Entry<BluetoothHealthAppConfiguration, String> e :
+ mHealthAppConfigs.entrySet()) {
+ if (e.getValue().equals(configPath)) {
+ config = e.getKey();
+ }
}
- }
- if (config == null) {
- errorLog("No associated application for application path:" + configPath);
- return null;
+ if (config == null) errorLog("No associated application for path:" + configPath);
}
}
return config;
@@ -375,78 +425,85 @@
if (address == null) return;
BluetoothDevice device = adapter.getRemoteDevice(address);
-
- BluetoothHealthAppConfiguration config = findHealthApplication(device,
- channelPath);
+ BluetoothHealthAppConfiguration config;
int state, prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
ParcelFileDescriptor fd;
HealthChannel channel;
+ config = findHealthApplication(device, channelPath);
- if (config != null) {
- if (exists) {
- fd = mBluetoothService.getChannelFdNative(channelPath);
+ if (exists) {
+ channel = findConnectingChannel(device, config);
+ if (channel == null) {
+ channel = new HealthChannel(device, config, null, false,
+ channelPath);
+ channel.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
+ mHealthChannels.add(channel);
+ }
+ channel.mChannelPath = channelPath;
- if (fd == null) {
- errorLog("Error obtaining fd for channel:" + channelPath);
- return;
- }
+ fd = mBluetoothService.getChannelFdNative(channelPath);
+ if (fd == null) {
+ errorLog("Error obtaining fd for channel:" + channelPath);
+ disconnectChannel(device, config, channel.hashCode());
+ return;
+ }
+ boolean mainChannel =
+ getMainChannel(device, config) == null ? false : true;
+ if (!mainChannel) {
+ String mainChannelPath =
+ mBluetoothService.getMainChannelNative(devicePath);
+ if (mainChannelPath == null) {
+ errorLog("Main Channel Path is null for devicePath:" + devicePath);
+ return;
+ }
+ if (mainChannelPath.equals(channelPath)) mainChannel = true;
+ }
- boolean mainChannel =
- getMainChannel(device, config) == null ? false : true;
- if (!mainChannel) {
- String mainChannelPath =
- mBluetoothService.getMainChannelNative(devicePath);
- if (mainChannelPath == null) {
- errorLog("Main Channel Path is null for devicePath:" + devicePath);
- return;
- }
- if (mainChannelPath.equals(channelPath)) mainChannel = true;
- }
+ channel.mChannelFd = fd;
+ channel.mMainChannel = mainChannel;
+ prevState = channel.mState;
+ state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
+ } else {
+ channel = findChannelByPath(device, channelPath);
+ if (channel == null) {
+ errorLog("Channel not found:" + config + ":" + channelPath);
+ return;
+ }
+ mHealthChannels.remove(channel);
- channel = findConnectingChannel(device, config);
- if (channel != null) {
- channel.mChannelFd = fd;
- channel.mMainChannel = mainChannel;
- channel.mChannelPath = channelPath;
- prevState = channel.mState;
- } else {
- channel = new HealthChannel(device, config, fd, mainChannel,
- channelPath);
- mHealthChannels.add(channel);
- prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
- }
- state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
- } else {
- channel = findChannelByPath(device, config, channelPath);
- if (channel == null) {
- errorLog("Channel not found:" + config + ":" + channelPath);
- return;
- }
-
- fd = channel.mChannelFd;
- // CLOSE FD
- mBluetoothService.releaseChannelFdNative(channel.mChannelPath);
- mHealthChannels.remove(channel);
-
- prevState = channel.mState;
- state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
- }
- channel.mState = state;
- callHealthChannelCallback(config, device, prevState, state, fd);
+ channel.mChannelFd = null;
+ prevState = channel.mState;
+ state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
}
+ channel.mState = state;
+ callHealthChannelCallback(config, device, prevState, state, channel.mChannelFd,
+ channel.hashCode());
}
private void callHealthChannelCallback(BluetoothHealthAppConfiguration config,
- BluetoothDevice device, int prevState, int state, ParcelFileDescriptor fd) {
+ BluetoothDevice device, int prevState, int state, ParcelFileDescriptor fd, int id) {
broadcastHealthDeviceStateChange(device, prevState, state);
debugLog("Health Device Callback: " + device + " State Change: "
+ prevState + "->" + state);
+
+ ParcelFileDescriptor dupedFd = null;
+ if (fd != null) {
+ try {
+ dupedFd = fd.dup();
+ } catch (IOException e) {
+ dupedFd = null;
+ errorLog("Exception while duping: " + e);
+ }
+ }
+
IBluetoothHealthCallback callback = mCallbacks.get(config);
if (callback != null) {
try {
- callback.onHealthChannelStateChange(config, device, prevState, state, fd);
- } catch (RemoteException e) {}
+ callback.onHealthChannelStateChange(config, device, prevState, state, dupedFd, id);
+ } catch (RemoteException e) {
+ errorLog("Remote Exception:" + e);
+ }
}
}
@@ -458,7 +515,9 @@
if (callback != null) {
try {
callback.onHealthAppConfigurationStatusChange(config, status);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ errorLog("Remote Exception:" + e);
+ }
}
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 55a0624..00d3331 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -95,7 +95,6 @@
private boolean mIsAirplaneSensitive;
private boolean mIsAirplaneToggleable;
private BluetoothAdapterStateMachine mBluetoothState;
- private boolean mRestart = false; // need to call enable() after disable()
private int[] mAdapterSdpHandles;
private ParcelUuid[] mAdapterUuids;
@@ -429,11 +428,6 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- if (mRestart) {
- mRestart = false;
- enable();
- }
}
/**
@@ -456,10 +450,6 @@
// the adapter property could be changed before event loop is stoped, clear it again
mAdapterProperties.clear();
disableNative();
- if (mRestart) {
- mRestart = false;
- enable();
- }
}
/** Bring up BT and persist BT on in settings */
@@ -500,17 +490,6 @@
return true;
}
- /** Forcibly restart Bluetooth if it is on */
- /* package */ synchronized void restart() {
- if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
- return;
- }
- mRestart = true;
- if (!disable(false)) {
- mRestart = false;
- }
- }
-
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -2243,11 +2222,11 @@
}
public boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+ BluetoothHealthAppConfiguration config, int id) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
synchronized (mBluetoothHealthProfileHandler) {
- return mBluetoothHealthProfileHandler.disconnectChannel(device, config, fd);
+ return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id);
}
}
@@ -2276,6 +2255,14 @@
}
}
+ /*package*/ void onHealthDeviceChannelConnectionError(int channelCode,
+ int newState) {
+ synchronized(mBluetoothHealthProfileHandler) {
+ mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode,
+ newState);
+ }
+ }
+
public int getHealthDeviceConnectionState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
@@ -2806,8 +2793,9 @@
String channelType);
native String registerHealthApplicationNative(int dataType, String role, String name);
native boolean unregisterHealthApplicationNative(String path);
- native boolean createChannelNative(String devicePath, String appPath, String channelType);
- native boolean destroyChannelNative(String devicePath, String channelpath);
+ native boolean createChannelNative(String devicePath, String appPath, String channelType,
+ int code);
+ native boolean destroyChannelNative(String devicePath, String channelpath, int code);
native String getMainChannelNative(String path);
native String getChannelApplicationNative(String channelPath);
native ParcelFileDescriptor getChannelFdNative(String channelPath);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 39f9367..713bb91 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -36,6 +36,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -716,7 +717,9 @@
mSession = ViewRootImpl.getWindowSession(getMainLooper());
mWindow.setSession(mSession);
-
+
+ mScreenOn = ((PowerManager)getSystemService(Context.POWER_SERVICE)).isScreenOn();
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index a08ba2a..48739ba 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -260,6 +260,17 @@
return old;
}
+ private synchronized SpeechItem maybeRemoveCurrentSpeechItem(String callingApp) {
+ if (mCurrentSpeechItem != null &&
+ TextUtils.equals(mCurrentSpeechItem.getCallingApp(), callingApp)) {
+ SpeechItem current = mCurrentSpeechItem;
+ mCurrentSpeechItem = null;
+ return current;
+ }
+
+ return null;
+ }
+
public boolean isSpeaking() {
return getCurrentSpeechItem() != null;
}
@@ -287,14 +298,9 @@
}
if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(speechItem.getCallingApp());
+ stopForApp(speechItem.getCallingApp());
} else if (queueMode == TextToSpeech.QUEUE_DESTROY) {
- // Stop the current speech item.
- stop(speechItem.getCallingApp());
- // Remove all other items from the queue.
- removeCallbacksAndMessages(null);
- // Remove all pending playback as well.
- mAudioPlaybackHandler.removeAllItems();
+ stopAll();
}
Runnable runnable = new Runnable() {
@Override
@@ -305,7 +311,8 @@
}
};
Message msg = Message.obtain(this, runnable);
- // The obj is used to remove all callbacks from the given app in stop(String).
+ // The obj is used to remove all callbacks from the given app in
+ // stopForApp(String).
//
// Note that this string is interned, so the == comparison works.
msg.obj = speechItem.getCallingApp();
@@ -323,7 +330,7 @@
*
* Called on a service binder thread.
*/
- public int stop(String callingApp) {
+ public int stopForApp(String callingApp) {
if (TextUtils.isEmpty(callingApp)) {
return TextToSpeech.ERROR;
}
@@ -331,8 +338,13 @@
removeCallbacksAndMessages(callingApp);
// This stops writing data to the file / or publishing
// items to the audio playback handler.
- SpeechItem current = setCurrentSpeechItem(null);
- if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
+ //
+ // Note that the current speech item must be removed only if it
+ // belongs to the callingApp, else the item will be "orphaned" and
+ // not stopped correctly if a stop request comes along for the item
+ // from the app it belongs to.
+ SpeechItem current = maybeRemoveCurrentSpeechItem(callingApp);
+ if (current != null) {
current.stop();
}
@@ -341,6 +353,20 @@
return TextToSpeech.SUCCESS;
}
+
+ public int stopAll() {
+ // Stop the current speech item unconditionally.
+ SpeechItem current = setCurrentSpeechItem(null);
+ if (current != null) {
+ current.stop();
+ }
+ // Remove all other items from the queue.
+ removeCallbacksAndMessages(null);
+ // Remove all pending playback as well.
+ mAudioPlaybackHandler.removeAllItems();
+
+ return TextToSpeech.SUCCESS;
+ }
}
interface UtteranceCompletedDispatcher {
@@ -412,6 +438,10 @@
}
}
+ protected synchronized boolean isStopped() {
+ return mStopped;
+ }
+
protected abstract int playImpl();
protected abstract void stopImpl();
@@ -473,7 +503,7 @@
Log.w(TAG, "Got empty text");
return false;
}
- if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){
+ if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH) {
Log.w(TAG, "Text too long: " + mText.length() + " chars");
return false;
}
@@ -485,6 +515,11 @@
AbstractSynthesisCallback synthesisCallback;
mEventLogger.onRequestProcessingStart();
synchronized (this) {
+ // stop() might have been called before we enter this
+ // synchronized block.
+ if (isStopped()) {
+ return TextToSpeech.ERROR;
+ }
mSynthesisCallback = createSynthesisCallback();
synthesisCallback = mSynthesisCallback;
}
@@ -510,8 +545,13 @@
synchronized (this) {
synthesisCallback = mSynthesisCallback;
}
- synthesisCallback.stop();
- TextToSpeechService.this.onStop();
+ if (synthesisCallback != null) {
+ // If the synthesis callback is null, it implies that we haven't
+ // entered the synchronized(this) block in playImpl which in
+ // turn implies that synthesis would not have started.
+ synthesisCallback.stop();
+ TextToSpeechService.this.onStop();
+ }
}
public String getLanguage() {
@@ -719,7 +759,7 @@
return TextToSpeech.ERROR;
}
- return mSynthHandler.stop(intern(callingApp));
+ return mSynthHandler.stopForApp(intern(callingApp));
}
public String[] getLanguage() {
@@ -811,7 +851,7 @@
synchronized (mAppToCallback) {
mAppToCallback.remove(packageName);
}
- mSynthHandler.stop(packageName);
+ mSynthHandler.stopForApp(packageName);
}
@Override
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index 625d869..afd9892 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -72,8 +72,15 @@
linkColor = tp.linkColor;
drawableState = tp.drawableState;
density = tp.density;
- underlineColors = tp.underlineColors;
- underlineThicknesses = tp.underlineThicknesses;
+
+ if (tp.underlineColors != null) {
+ if (underlineColors == null || underlineColors.length < tp.underlineCount) {
+ underlineColors = new int[tp.underlineCount];
+ underlineThicknesses = new float[tp.underlineCount];
+ }
+ System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount);
+ System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount);
+ }
underlineCount = tp.underlineCount;
}
diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java
index a637b1c..2dbfc72 100644
--- a/core/java/android/text/style/SuggestionRangeSpan.java
+++ b/core/java/android/text/style/SuggestionRangeSpan.java
@@ -28,15 +28,11 @@
* @hide
*/
public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan {
- private final int mBackgroundColor;
+ private int mBackgroundColor;
- @Override
- public void updateDrawState(TextPaint tp) {
- tp.bgColor = mBackgroundColor;
- }
-
- public SuggestionRangeSpan(int color) {
- mBackgroundColor = color;
+ public SuggestionRangeSpan() {
+ // 0 is a fully transparent black. Has to be set using #setBackgroundColor
+ mBackgroundColor = 0;
}
public SuggestionRangeSpan(Parcel src) {
@@ -57,4 +53,13 @@
public int getSpanTypeId() {
return TextUtils.SUGGESTION_RANGE_SPAN;
}
+
+ public void setBackgroundColor(int backgroundColor) {
+ mBackgroundColor = backgroundColor;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ tp.bgColor = mBackgroundColor;
+ }
}
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 693a7a9..51e9d7d 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -264,4 +264,16 @@
tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
}
}
+
+ /**
+ * @return The color of the underline for that span, or 0 if there is no underline
+ *
+ * @hide
+ */
+ public int getUnderlineColor() {
+ // The order here should match what is used in updateDrawState
+ if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor;
+ if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor;
+ return 0;
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ba23218..eedf19f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,6 +27,7 @@
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -68,6 +69,8 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.ScrollBarDrawable;
+import static android.os.Build.VERSION_CODES.*;
+
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
@@ -584,7 +587,7 @@
* @attr ref android.R.styleable#View_drawingCacheQuality
* @attr ref android.R.styleable#View_duplicateParentState
* @attr ref android.R.styleable#View_id
- * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_requiresFadingEdge
* @attr ref android.R.styleable#View_fadingEdgeLength
* @attr ref android.R.styleable#View_filterTouchesWhenObscured
* @attr ref android.R.styleable#View_fitsSystemWindows
@@ -636,7 +639,8 @@
*
* @see android.view.ViewGroup
*/
-public class View implements Drawable.Callback2, KeyEvent.Callback, AccessibilityEventSource {
+public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Callback,
+ AccessibilityEventSource {
private static final boolean DBG = false;
/**
@@ -2000,64 +2004,133 @@
@ViewDebug.ExportedProperty
int mViewFlags;
- /**
- * The transform matrix for the View. This transform is calculated internally
- * based on the rotation, scaleX, and scaleY properties. The identity matrix
- * is used by default. Do *not* use this variable directly; instead call
- * getMatrix(), which will automatically recalculate the matrix if necessary
- * to get the correct matrix based on the latest rotation and scale properties.
- */
- private final Matrix mMatrix = new Matrix();
+ static class TransformationInfo {
+ /**
+ * The transform matrix for the View. This transform is calculated internally
+ * based on the rotation, scaleX, and scaleY properties. The identity matrix
+ * is used by default. Do *not* use this variable directly; instead call
+ * getMatrix(), which will automatically recalculate the matrix if necessary
+ * to get the correct matrix based on the latest rotation and scale properties.
+ */
+ private final Matrix mMatrix = new Matrix();
- /**
- * The transform matrix for the View. This transform is calculated internally
- * based on the rotation, scaleX, and scaleY properties. The identity matrix
- * is used by default. Do *not* use this variable directly; instead call
- * getInverseMatrix(), which will automatically recalculate the matrix if necessary
- * to get the correct matrix based on the latest rotation and scale properties.
- */
- private Matrix mInverseMatrix;
+ /**
+ * The transform matrix for the View. This transform is calculated internally
+ * based on the rotation, scaleX, and scaleY properties. The identity matrix
+ * is used by default. Do *not* use this variable directly; instead call
+ * getInverseMatrix(), which will automatically recalculate the matrix if necessary
+ * to get the correct matrix based on the latest rotation and scale properties.
+ */
+ private Matrix mInverseMatrix;
- /**
- * An internal variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated.
- */
- boolean mMatrixDirty = false;
+ /**
+ * An internal variable that tracks whether we need to recalculate the
+ * transform matrix, based on whether the rotation or scaleX/Y properties
+ * have changed since the matrix was last calculated.
+ */
+ boolean mMatrixDirty = false;
- /**
- * An internal variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated.
- */
- private boolean mInverseMatrixDirty = true;
+ /**
+ * An internal variable that tracks whether we need to recalculate the
+ * transform matrix, based on whether the rotation or scaleX/Y properties
+ * have changed since the matrix was last calculated.
+ */
+ private boolean mInverseMatrixDirty = true;
- /**
- * A variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated. This variable
- * is only valid after a call to updateMatrix() or to a function that
- * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
- */
- private boolean mMatrixIsIdentity = true;
+ /**
+ * A variable that tracks whether we need to recalculate the
+ * transform matrix, based on whether the rotation or scaleX/Y properties
+ * have changed since the matrix was last calculated. This variable
+ * is only valid after a call to updateMatrix() or to a function that
+ * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
+ */
+ private boolean mMatrixIsIdentity = true;
- /**
- * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set.
- */
- private Camera mCamera = null;
+ /**
+ * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set.
+ */
+ private Camera mCamera = null;
- /**
- * This matrix is used when computing the matrix for 3D rotations.
- */
- private Matrix matrix3D = null;
+ /**
+ * This matrix is used when computing the matrix for 3D rotations.
+ */
+ private Matrix matrix3D = null;
- /**
- * These prev values are used to recalculate a centered pivot point when necessary. The
- * pivot point is only used in matrix operations (when rotation, scale, or translation are
- * set), so thes values are only used then as well.
- */
- private int mPrevWidth = -1;
- private int mPrevHeight = -1;
+ /**
+ * These prev values are used to recalculate a centered pivot point when necessary. The
+ * pivot point is only used in matrix operations (when rotation, scale, or translation are
+ * set), so thes values are only used then as well.
+ */
+ private int mPrevWidth = -1;
+ private int mPrevHeight = -1;
+
+ /**
+ * The degrees rotation around the vertical axis through the pivot point.
+ */
+ @ViewDebug.ExportedProperty
+ float mRotationY = 0f;
+
+ /**
+ * The degrees rotation around the horizontal axis through the pivot point.
+ */
+ @ViewDebug.ExportedProperty
+ float mRotationX = 0f;
+
+ /**
+ * The degrees rotation around the pivot point.
+ */
+ @ViewDebug.ExportedProperty
+ float mRotation = 0f;
+
+ /**
+ * The amount of translation of the object away from its left property (post-layout).
+ */
+ @ViewDebug.ExportedProperty
+ float mTranslationX = 0f;
+
+ /**
+ * The amount of translation of the object away from its top property (post-layout).
+ */
+ @ViewDebug.ExportedProperty
+ float mTranslationY = 0f;
+
+ /**
+ * The amount of scale in the x direction around the pivot point. A
+ * value of 1 means no scaling is applied.
+ */
+ @ViewDebug.ExportedProperty
+ float mScaleX = 1f;
+
+ /**
+ * The amount of scale in the y direction around the pivot point. A
+ * value of 1 means no scaling is applied.
+ */
+ @ViewDebug.ExportedProperty
+ float mScaleY = 1f;
+
+ /**
+ * The amount of scale in the x direction around the pivot point. A
+ * value of 1 means no scaling is applied.
+ */
+ @ViewDebug.ExportedProperty
+ float mPivotX = 0f;
+
+ /**
+ * The amount of scale in the y direction around the pivot point. A
+ * value of 1 means no scaling is applied.
+ */
+ @ViewDebug.ExportedProperty
+ float mPivotY = 0f;
+
+ /**
+ * The opacity of the View. This is a value from 0 to 1, where 0 means
+ * completely transparent and 1 means completely opaque.
+ */
+ @ViewDebug.ExportedProperty
+ float mAlpha = 1f;
+ }
+
+ TransformationInfo mTransformationInfo;
private boolean mLastIsOpaque;
@@ -2068,71 +2141,6 @@
private static final float NONZERO_EPSILON = .001f;
/**
- * The degrees rotation around the vertical axis through the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotationY = 0f;
-
- /**
- * The degrees rotation around the horizontal axis through the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotationX = 0f;
-
- /**
- * The degrees rotation around the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotation = 0f;
-
- /**
- * The amount of translation of the object away from its left property (post-layout).
- */
- @ViewDebug.ExportedProperty
- float mTranslationX = 0f;
-
- /**
- * The amount of translation of the object away from its top property (post-layout).
- */
- @ViewDebug.ExportedProperty
- float mTranslationY = 0f;
-
- /**
- * The amount of scale in the x direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mScaleX = 1f;
-
- /**
- * The amount of scale in the y direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mScaleY = 1f;
-
- /**
- * The amount of scale in the x direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mPivotX = 0f;
-
- /**
- * The amount of scale in the y direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mPivotY = 0f;
-
- /**
- * The opacity of the View. This is a value from 0 to 1, where 0 means
- * completely transparent and 1 means completely opaque.
- */
- @ViewDebug.ExportedProperty
- float mAlpha = 1f;
-
- /**
* The distance in pixels from the left edge of this view's parent
* to the left edge of this view.
* {@hide}
@@ -2583,6 +2591,8 @@
/**
* Default text direction is inherited
+ *
+ * @hide
*/
protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
@@ -2887,6 +2897,12 @@
}
break;
case R.styleable.View_fadingEdge:
+ if (context.getApplicationInfo().targetSdkVersion >= ICE_CREAM_SANDWICH) {
+ // Ignore the attribute starting with ICS
+ break;
+ }
+ // With builds < ICS, fall through and apply fading edges
+ case R.styleable.View_requiresFadingEdge:
final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE);
if (fadingEdge != FADING_EDGE_NONE) {
viewFlagValues |= fadingEdge;
@@ -6773,8 +6789,11 @@
* @return The current transform matrix for the view
*/
public Matrix getMatrix() {
- updateMatrix();
- return mMatrix;
+ if (mTransformationInfo != null) {
+ updateMatrix();
+ return mTransformationInfo.mMatrix;
+ }
+ return Matrix.IDENTITY_MATRIX;
}
/**
@@ -6794,49 +6813,63 @@
* @return True if the transform matrix is the identity matrix, false otherwise.
*/
final boolean hasIdentityMatrix() {
- updateMatrix();
- return mMatrixIsIdentity;
+ if (mTransformationInfo != null) {
+ updateMatrix();
+ return mTransformationInfo.mMatrixIsIdentity;
+ }
+ return true;
+ }
+
+ void ensureTransformationInfo() {
+ if (mTransformationInfo == null) {
+ mTransformationInfo = new TransformationInfo();
+ }
}
/**
* Recomputes the transform matrix if necessary.
*/
private void updateMatrix() {
- if (mMatrixDirty) {
+ final TransformationInfo info = mTransformationInfo;
+ if (info == null) {
+ return;
+ }
+ if (info.mMatrixDirty) {
// transform-related properties have changed since the last time someone
// asked for the matrix; recalculate it with the current values
// Figure out if we need to update the pivot point
if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
- if ((mRight - mLeft) != mPrevWidth || (mBottom - mTop) != mPrevHeight) {
- mPrevWidth = mRight - mLeft;
- mPrevHeight = mBottom - mTop;
- mPivotX = mPrevWidth / 2f;
- mPivotY = mPrevHeight / 2f;
+ if ((mRight - mLeft) != info.mPrevWidth || (mBottom - mTop) != info.mPrevHeight) {
+ info.mPrevWidth = mRight - mLeft;
+ info.mPrevHeight = mBottom - mTop;
+ info.mPivotX = info.mPrevWidth / 2f;
+ info.mPivotY = info.mPrevHeight / 2f;
}
}
- mMatrix.reset();
- if (!nonzero(mRotationX) && !nonzero(mRotationY)) {
- mMatrix.setTranslate(mTranslationX, mTranslationY);
- mMatrix.preRotate(mRotation, mPivotX, mPivotY);
- mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ info.mMatrix.reset();
+ if (!nonzero(info.mRotationX) && !nonzero(info.mRotationY)) {
+ info.mMatrix.setTranslate(info.mTranslationX, info.mTranslationY);
+ info.mMatrix.preRotate(info.mRotation, info.mPivotX, info.mPivotY);
+ info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
} else {
- if (mCamera == null) {
- mCamera = new Camera();
- matrix3D = new Matrix();
+ if (info.mCamera == null) {
+ info.mCamera = new Camera();
+ info.matrix3D = new Matrix();
}
- mCamera.save();
- mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
- mCamera.rotate(mRotationX, mRotationY, -mRotation);
- mCamera.getMatrix(matrix3D);
- matrix3D.preTranslate(-mPivotX, -mPivotY);
- matrix3D.postTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY);
- mMatrix.postConcat(matrix3D);
- mCamera.restore();
+ info.mCamera.save();
+ info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
+ info.mCamera.rotate(info.mRotationX, info.mRotationY, -info.mRotation);
+ info.mCamera.getMatrix(info.matrix3D);
+ info.matrix3D.preTranslate(-info.mPivotX, -info.mPivotY);
+ info.matrix3D.postTranslate(info.mPivotX + info.mTranslationX,
+ info.mPivotY + info.mTranslationY);
+ info.mMatrix.postConcat(info.matrix3D);
+ info.mCamera.restore();
}
- mMatrixDirty = false;
- mMatrixIsIdentity = mMatrix.isIdentity();
- mInverseMatrixDirty = true;
+ info.mMatrixDirty = false;
+ info.mMatrixIsIdentity = info.mMatrix.isIdentity();
+ info.mInverseMatrixDirty = true;
}
}
@@ -6848,15 +6881,19 @@
* @return The inverse of the current matrix of this view.
*/
final Matrix getInverseMatrix() {
- updateMatrix();
- if (mInverseMatrixDirty) {
- if (mInverseMatrix == null) {
- mInverseMatrix = new Matrix();
+ final TransformationInfo info = mTransformationInfo;
+ if (info != null) {
+ updateMatrix();
+ if (info.mInverseMatrixDirty) {
+ if (info.mInverseMatrix == null) {
+ info.mInverseMatrix = new Matrix();
+ }
+ info.mMatrix.invert(info.mInverseMatrix);
+ info.mInverseMatrixDirty = false;
}
- mMatrix.invert(mInverseMatrix);
- mInverseMatrixDirty = false;
+ return info.mInverseMatrix;
}
- return mInverseMatrix;
+ return Matrix.IDENTITY_MATRIX;
}
/**
@@ -6902,14 +6939,16 @@
invalidateParentCaches();
invalidate(false);
+ ensureTransformationInfo();
final float dpi = mResources.getDisplayMetrics().densityDpi;
- if (mCamera == null) {
- mCamera = new Camera();
- matrix3D = new Matrix();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mCamera == null) {
+ info.mCamera = new Camera();
+ info.matrix3D = new Matrix();
}
- mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
- mMatrixDirty = true;
+ info.mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
+ info.mMatrixDirty = true;
invalidate(false);
}
@@ -6924,7 +6963,7 @@
* @return The degrees of rotation.
*/
public float getRotation() {
- return mRotation;
+ return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
}
/**
@@ -6942,12 +6981,14 @@
* @attr ref android.R.styleable#View_rotation
*/
public void setRotation(float rotation) {
- if (mRotation != rotation) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mRotation != rotation) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mRotation = rotation;
- mMatrixDirty = true;
+ info.mRotation = rotation;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -6963,7 +7004,7 @@
* @return The degrees of Y rotation.
*/
public float getRotationY() {
- return mRotationY;
+ return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
}
/**
@@ -6986,12 +7027,14 @@
* @attr ref android.R.styleable#View_rotationY
*/
public void setRotationY(float rotationY) {
- if (mRotationY != rotationY) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mRotationY != rotationY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mRotationY = rotationY;
- mMatrixDirty = true;
+ info.mRotationY = rotationY;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7007,7 +7050,7 @@
* @return The degrees of X rotation.
*/
public float getRotationX() {
- return mRotationX;
+ return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
}
/**
@@ -7030,12 +7073,14 @@
* @attr ref android.R.styleable#View_rotationX
*/
public void setRotationX(float rotationX) {
- if (mRotationX != rotationX) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mRotationX != rotationX) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mRotationX = rotationX;
- mMatrixDirty = true;
+ info.mRotationX = rotationX;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7052,7 +7097,7 @@
* @return The scaling factor.
*/
public float getScaleX() {
- return mScaleX;
+ return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
}
/**
@@ -7066,12 +7111,14 @@
* @attr ref android.R.styleable#View_scaleX
*/
public void setScaleX(float scaleX) {
- if (mScaleX != scaleX) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mScaleX != scaleX) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mScaleX = scaleX;
- mMatrixDirty = true;
+ info.mScaleX = scaleX;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7088,7 +7135,7 @@
* @return The scaling factor.
*/
public float getScaleY() {
- return mScaleY;
+ return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
}
/**
@@ -7102,12 +7149,14 @@
* @attr ref android.R.styleable#View_scaleY
*/
public void setScaleY(float scaleY) {
- if (mScaleY != scaleY) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mScaleY != scaleY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mScaleY = scaleY;
- mMatrixDirty = true;
+ info.mScaleY = scaleY;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7124,7 +7173,7 @@
* @return The x location of the pivot point.
*/
public float getPivotX() {
- return mPivotX;
+ return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
}
/**
@@ -7143,13 +7192,15 @@
* @attr ref android.R.styleable#View_transformPivotX
*/
public void setPivotX(float pivotX) {
+ ensureTransformationInfo();
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
- if (mPivotX != pivotX) {
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mPivotX != pivotX) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mPivotX = pivotX;
- mMatrixDirty = true;
+ info.mPivotX = pivotX;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7166,7 +7217,7 @@
* @return The y location of the pivot point.
*/
public float getPivotY() {
- return mPivotY;
+ return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
}
/**
@@ -7184,13 +7235,15 @@
* @attr ref android.R.styleable#View_transformPivotY
*/
public void setPivotY(float pivotY) {
+ ensureTransformationInfo();
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
- if (mPivotY != pivotY) {
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mPivotY != pivotY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mPivotY = pivotY;
- mMatrixDirty = true;
+ info.mPivotY = pivotY;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7204,7 +7257,7 @@
* @return The opacity of the view.
*/
public float getAlpha() {
- return mAlpha;
+ return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
}
/**
@@ -7223,7 +7276,8 @@
* @attr ref android.R.styleable#View_alpha
*/
public void setAlpha(float alpha) {
- mAlpha = alpha;
+ ensureTransformationInfo();
+ mTransformationInfo.mAlpha = alpha;
invalidateParentCaches();
if (onSetAlpha((int) (alpha * 255))) {
mPrivateFlags |= ALPHA_SET;
@@ -7245,7 +7299,8 @@
* @return true if the View subclass handles alpha (the return value for onSetAlpha())
*/
boolean setAlphaNoInvalidation(float alpha) {
- mAlpha = alpha;
+ ensureTransformationInfo();
+ mTransformationInfo.mAlpha = alpha;
boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
if (subclassHandlesAlpha) {
mPrivateFlags |= ALPHA_SET;
@@ -7275,7 +7330,9 @@
public final void setTop(int top) {
if (top != mTop) {
updateMatrix();
- if (mMatrixIsIdentity) {
+ final boolean matrixIsIdentity = mTransformationInfo == null
+ || mTransformationInfo.mMatrixIsIdentity;
+ if (matrixIsIdentity) {
if (mAttachInfo != null) {
int minTop;
int yLoc;
@@ -7300,10 +7357,10 @@
onSizeChanged(width, mBottom - mTop, width, oldHeight);
- if (!mMatrixIsIdentity) {
+ if (!matrixIsIdentity) {
if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
// A change in dimension means an auto-centered pivot point changes, too
- mMatrixDirty = true;
+ mTransformationInfo.mMatrixDirty = true;
}
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(true);
@@ -7342,7 +7399,9 @@
public final void setBottom(int bottom) {
if (bottom != mBottom) {
updateMatrix();
- if (mMatrixIsIdentity) {
+ final boolean matrixIsIdentity = mTransformationInfo == null
+ || mTransformationInfo.mMatrixIsIdentity;
+ if (matrixIsIdentity) {
if (mAttachInfo != null) {
int maxBottom;
if (bottom < mBottom) {
@@ -7364,10 +7423,10 @@
onSizeChanged(width, mBottom - mTop, width, oldHeight);
- if (!mMatrixIsIdentity) {
+ if (!matrixIsIdentity) {
if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
// A change in dimension means an auto-centered pivot point changes, too
- mMatrixDirty = true;
+ mTransformationInfo.mMatrixDirty = true;
}
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(true);
@@ -7397,7 +7456,9 @@
public final void setLeft(int left) {
if (left != mLeft) {
updateMatrix();
- if (mMatrixIsIdentity) {
+ final boolean matrixIsIdentity = mTransformationInfo == null
+ || mTransformationInfo.mMatrixIsIdentity;
+ if (matrixIsIdentity) {
if (mAttachInfo != null) {
int minLeft;
int xLoc;
@@ -7422,10 +7483,10 @@
onSizeChanged(mRight - mLeft, height, oldWidth, height);
- if (!mMatrixIsIdentity) {
+ if (!matrixIsIdentity) {
if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
// A change in dimension means an auto-centered pivot point changes, too
- mMatrixDirty = true;
+ mTransformationInfo.mMatrixDirty = true;
}
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(true);
@@ -7455,7 +7516,9 @@
public final void setRight(int right) {
if (right != mRight) {
updateMatrix();
- if (mMatrixIsIdentity) {
+ final boolean matrixIsIdentity = mTransformationInfo == null
+ || mTransformationInfo.mMatrixIsIdentity;
+ if (matrixIsIdentity) {
if (mAttachInfo != null) {
int maxRight;
if (right < mRight) {
@@ -7477,10 +7540,10 @@
onSizeChanged(mRight - mLeft, height, oldWidth, height);
- if (!mMatrixIsIdentity) {
+ if (!matrixIsIdentity) {
if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
// A change in dimension means an auto-centered pivot point changes, too
- mMatrixDirty = true;
+ mTransformationInfo.mMatrixDirty = true;
}
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(true);
@@ -7498,7 +7561,7 @@
* @return The visual x position of this view, in pixels.
*/
public float getX() {
- return mLeft + mTranslationX;
+ return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
}
/**
@@ -7520,7 +7583,7 @@
* @return The visual y position of this view, in pixels.
*/
public float getY() {
- return mTop + mTranslationY;
+ return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
}
/**
@@ -7543,7 +7606,7 @@
* @return The horizontal position of this view relative to its left position, in pixels.
*/
public float getTranslationX() {
- return mTranslationX;
+ return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
}
/**
@@ -7557,12 +7620,14 @@
* @attr ref android.R.styleable#View_translationX
*/
public void setTranslationX(float translationX) {
- if (mTranslationX != translationX) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mTranslationX != translationX) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mTranslationX = translationX;
- mMatrixDirty = true;
+ info.mTranslationX = translationX;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7577,7 +7642,7 @@
* in pixels.
*/
public float getTranslationY() {
- return mTranslationY;
+ return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
}
/**
@@ -7591,12 +7656,14 @@
* @attr ref android.R.styleable#View_translationY
*/
public void setTranslationY(float translationY) {
- if (mTranslationY != translationY) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mTranslationY != translationY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
- mTranslationY = translationY;
- mMatrixDirty = true;
+ info.mTranslationY = translationY;
+ info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7606,63 +7673,78 @@
* @hide
*/
public void setFastTranslationX(float x) {
- mTranslationX = x;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mTranslationX = x;
+ info.mMatrixDirty = true;
}
/**
* @hide
*/
public void setFastTranslationY(float y) {
- mTranslationY = y;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mTranslationY = y;
+ info.mMatrixDirty = true;
}
/**
* @hide
*/
public void setFastX(float x) {
- mTranslationX = x - mLeft;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mTranslationX = x - mLeft;
+ info.mMatrixDirty = true;
}
/**
* @hide
*/
public void setFastY(float y) {
- mTranslationY = y - mTop;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mTranslationY = y - mTop;
+ info.mMatrixDirty = true;
}
/**
* @hide
*/
public void setFastScaleX(float x) {
- mScaleX = x;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mScaleX = x;
+ info.mMatrixDirty = true;
}
/**
* @hide
*/
public void setFastScaleY(float y) {
- mScaleY = y;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mScaleY = y;
+ info.mMatrixDirty = true;
}
/**
* @hide
*/
public void setFastAlpha(float alpha) {
- mAlpha = alpha;
+ ensureTransformationInfo();
+ mTransformationInfo.mAlpha = alpha;
}
/**
* @hide
*/
public void setFastRotationY(float y) {
- mRotationY = y;
- mMatrixDirty = true;
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ info.mRotationY = y;
+ info.mMatrixDirty = true;
}
/**
@@ -7672,12 +7754,14 @@
*/
public void getHitRect(Rect outRect) {
updateMatrix();
- if (mMatrixIsIdentity || mAttachInfo == null) {
+ final TransformationInfo info = mTransformationInfo;
+ if (info == null || info.mMatrixIsIdentity || mAttachInfo == null) {
outRect.set(mLeft, mTop, mRight, mBottom);
} else {
final RectF tmpRect = mAttachInfo.mTmpTransformRect;
- tmpRect.set(-mPivotX, -mPivotY, getWidth() - mPivotX, getHeight() - mPivotY);
- mMatrix.mapRect(tmpRect);
+ tmpRect.set(-info.mPivotX, -info.mPivotY,
+ getWidth() - info.mPivotX, getHeight() - info.mPivotY);
+ info.mMatrix.mapRect(tmpRect);
outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
(int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
}
@@ -7765,7 +7849,9 @@
public void offsetTopAndBottom(int offset) {
if (offset != 0) {
updateMatrix();
- if (mMatrixIsIdentity) {
+ final boolean matrixIsIdentity = mTransformationInfo == null
+ || mTransformationInfo.mMatrixIsIdentity;
+ if (matrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -7791,7 +7877,7 @@
mTop += offset;
mBottom += offset;
- if (!mMatrixIsIdentity) {
+ if (!matrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -7807,7 +7893,9 @@
public void offsetLeftAndRight(int offset) {
if (offset != 0) {
updateMatrix();
- if (mMatrixIsIdentity) {
+ final boolean matrixIsIdentity = mTransformationInfo == null
+ || mTransformationInfo.mMatrixIsIdentity;
+ if (matrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -7830,7 +7918,7 @@
mLeft += offset;
mRight += offset;
- if (!mMatrixIsIdentity) {
+ if (!matrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
@@ -8105,6 +8193,7 @@
(mPrivateFlags & INVALIDATED) != INVALIDATED) {
mPrivateFlags &= ~DRAWING_CACHE_VALID;
mPrivateFlags |= INVALIDATED;
+ mPrivateFlags |= DIRTY;
final ViewParent p = mParent;
final AttachInfo ai = mAttachInfo;
//noinspection PointlessBooleanExpression,ConstantConditions
@@ -8151,6 +8240,7 @@
(mPrivateFlags & INVALIDATED) != INVALIDATED) {
mPrivateFlags &= ~DRAWING_CACHE_VALID;
mPrivateFlags |= INVALIDATED;
+ mPrivateFlags |= DIRTY;
final ViewParent p = mParent;
final AttachInfo ai = mAttachInfo;
//noinspection PointlessBooleanExpression,ConstantConditions
@@ -8206,6 +8296,7 @@
(mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
mLastIsOpaque = isOpaque();
mPrivateFlags &= ~DRAWN;
+ mPrivateFlags |= DIRTY;
if (invalidateCache) {
mPrivateFlags |= INVALIDATED;
mPrivateFlags &= ~DRAWING_CACHE_VALID;
@@ -8246,6 +8337,7 @@
((View) mParent).mPrivateFlags |= INVALIDATED;
}
mPrivateFlags &= ~DRAWN;
+ mPrivateFlags |= DIRTY;
mPrivateFlags |= INVALIDATED;
mPrivateFlags &= ~DRAWING_CACHE_VALID;
if (mParent != null && mAttachInfo != null) {
@@ -8306,7 +8398,8 @@
@ViewDebug.ExportedProperty(category = "drawing")
public boolean isOpaque() {
return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK &&
- (mAlpha >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
+ ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1)
+ >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
}
/**
@@ -8561,7 +8654,7 @@
* otherwise
*
* @see #setHorizontalFadingEdgeEnabled(boolean)
- * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_requiresFadingEdge
*/
public boolean isHorizontalFadingEdgeEnabled() {
return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL;
@@ -8576,7 +8669,7 @@
* horizontally
*
* @see #isHorizontalFadingEdgeEnabled()
- * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_requiresFadingEdge
*/
public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) {
@@ -8596,7 +8689,7 @@
* otherwise
*
* @see #setVerticalFadingEdgeEnabled(boolean)
- * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_requiresFadingEdge
*/
public boolean isVerticalFadingEdgeEnabled() {
return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL;
@@ -8611,7 +8704,7 @@
* vertically
*
* @see #isVerticalFadingEdgeEnabled()
- * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_requiresFadingEdge
*/
public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) {
if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) {
@@ -9294,6 +9387,11 @@
recomputePadding();
}
+ /**
+ * Return true if layout direction resolution can be done
+ *
+ * @hide
+ */
protected boolean canResolveLayoutDirection() {
switch (getLayoutDirection()) {
case LAYOUT_DIRECTION_INHERIT:
@@ -9322,6 +9420,8 @@
*
* @param locale Locale to check
* @return true if a Locale is corresponding to a RTL script.
+ *
+ * @hide
*/
protected static boolean isLayoutDirectionRtl(Locale locale) {
return (LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE ==
@@ -9985,6 +10085,7 @@
}
final HardwareCanvas canvas = mDisplayList.start();
+ int restoreCount = 0;
try {
int width = mRight - mLeft;
int height = mBottom - mTop;
@@ -9994,6 +10095,8 @@
canvas.onPreDraw(null);
computeScroll();
+
+ restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
mPrivateFlags &= ~DIRTY_MASK;
@@ -10005,6 +10108,7 @@
draw(canvas);
}
} finally {
+ canvas.restoreToCount(restoreCount);
canvas.onPostDraw();
mDisplayList.end();
@@ -10940,7 +11044,9 @@
if (sizeChanged) {
if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
// A change in dimension means an auto-centered pivot point changes, too
- mMatrixDirty = true;
+ if (mTransformationInfo != null) {
+ mTransformationInfo.mMatrixDirty = true;
+ }
}
onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
}
@@ -11733,14 +11839,22 @@
+ "two integers");
}
- location[0] = mLeft + (int) (mTranslationX + 0.5f);
- location[1] = mTop + (int) (mTranslationY + 0.5f);
+ location[0] = mLeft;
+ location[1] = mTop;
+ if (mTransformationInfo != null) {
+ location[0] += (int) (mTransformationInfo.mTranslationX + 0.5f);
+ location[1] += (int) (mTransformationInfo.mTranslationY + 0.5f);
+ }
ViewParent viewParent = mParent;
while (viewParent instanceof View) {
final View view = (View)viewParent;
- location[0] += view.mLeft + (int) (view.mTranslationX + 0.5f) - view.mScrollX;
- location[1] += view.mTop + (int) (view.mTranslationY + 0.5f) - view.mScrollY;
+ location[0] += view.mLeft - view.mScrollX;
+ location[1] += view.mTop - view.mScrollY;
+ if (view.mTransformationInfo != null) {
+ location[0] += (int) (view.mTransformationInfo.mTranslationX + 0.5f);
+ location[1] += (int) (view.mTransformationInfo.mTranslationY + 0.5f);
+ }
viewParent = view.mParent;
}
@@ -13240,7 +13354,6 @@
* {@link #TEXT_DIRECTION_INHERIT},
* {@link #TEXT_DIRECTION_FIRST_STRONG}
* {@link #TEXT_DIRECTION_ANY_RTL},
- * {@link #TEXT_DIRECTION_CHAR_COUNT},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
*
@@ -13258,7 +13371,6 @@
* {@link #TEXT_DIRECTION_INHERIT},
* {@link #TEXT_DIRECTION_FIRST_STRONG}
* {@link #TEXT_DIRECTION_ANY_RTL},
- * {@link #TEXT_DIRECTION_CHAR_COUNT},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
*
@@ -13279,7 +13391,6 @@
*
* {@link #TEXT_DIRECTION_FIRST_STRONG}
* {@link #TEXT_DIRECTION_ANY_RTL},
- * {@link #TEXT_DIRECTION_CHAR_COUNT},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
*
@@ -13294,6 +13405,8 @@
/**
* Resolve the text direction.
+ *
+ * @hide
*/
protected void resolveTextDirection() {
if (mTextDirection != TEXT_DIRECTION_INHERIT) {
@@ -13309,6 +13422,8 @@
/**
* Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
+ *
+ * @hide
*/
protected void resetResolvedTextDirection() {
mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 6ed49ee..84dc7d8 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -51,7 +51,7 @@
* The View whose properties are being animated by this class. This is set at
* construction time.
*/
- private View mView;
+ private final View mView;
/**
* The duration of the underlying Animator object. By default, we don't set the duration
@@ -225,6 +225,7 @@
*/
ViewPropertyAnimator(View view) {
mView = view;
+ view.ensureTransformationInfo();
}
/**
@@ -721,36 +722,37 @@
* @param value The value to set the property to
*/
private void setValue(int propertyConstant, float value) {
+ final View.TransformationInfo info = mView.mTransformationInfo;
switch (propertyConstant) {
case TRANSLATION_X:
- mView.mTranslationX = value;
+ info.mTranslationX = value;
break;
case TRANSLATION_Y:
- mView.mTranslationY = value;
+ info.mTranslationY = value;
break;
case ROTATION:
- mView.mRotation = value;
+ info.mRotation = value;
break;
case ROTATION_X:
- mView.mRotationX = value;
+ info.mRotationX = value;
break;
case ROTATION_Y:
- mView.mRotationY = value;
+ info.mRotationY = value;
break;
case SCALE_X:
- mView.mScaleX = value;
+ info.mScaleX = value;
break;
case SCALE_Y:
- mView.mScaleY = value;
+ info.mScaleY = value;
break;
case X:
- mView.mTranslationX = value - mView.mLeft;
+ info.mTranslationX = value - mView.mLeft;
break;
case Y:
- mView.mTranslationY = value - mView.mTop;
+ info.mTranslationY = value - mView.mTop;
break;
case ALPHA:
- mView.mAlpha = value;
+ info.mAlpha = value;
break;
}
}
@@ -762,27 +764,28 @@
* @return float The value of the named property
*/
private float getValue(int propertyConstant) {
+ final View.TransformationInfo info = mView.mTransformationInfo;
switch (propertyConstant) {
case TRANSLATION_X:
- return mView.mTranslationX;
+ return info.mTranslationX;
case TRANSLATION_Y:
- return mView.mTranslationY;
+ return info.mTranslationY;
case ROTATION:
- return mView.mRotation;
+ return info.mRotation;
case ROTATION_X:
- return mView.mRotationX;
+ return info.mRotationX;
case ROTATION_Y:
- return mView.mRotationY;
+ return info.mRotationY;
case SCALE_X:
- return mView.mScaleX;
+ return info.mScaleX;
case SCALE_Y:
- return mView.mScaleY;
+ return info.mScaleY;
case X:
- return mView.mLeft + mView.mTranslationX;
+ return mView.mLeft + info.mTranslationX;
case Y:
- return mView.mTop + mView.mTranslationY;
+ return mView.mTop + info.mTranslationY;
case ALPHA:
- return mView.mAlpha;
+ return info.mAlpha;
}
return 0;
}
@@ -861,7 +864,7 @@
}
}
if ((propertyMask & TRANSFORM_MASK) != 0) {
- mView.mMatrixDirty = true;
+ mView.mTransformationInfo.mMatrixDirty = true;
mView.mPrivateFlags |= View.DRAWN; // force another invalidation
}
// invalidate(false) in all cases except if alphaHandled gets set to true
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0d160a9..fb3f6e8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -215,6 +215,7 @@
boolean mLastWasImTarget;
boolean mWindowAttributesChanged = false;
+ int mWindowAttributesChangesFlag = 0;
// These can be accessed by any thread, must be protected with a lock.
// Surface can never be reassigned or cleared (use Surface.clear()).
@@ -439,6 +440,7 @@
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
+ mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale =
@@ -640,7 +642,7 @@
// preserve compatible window flag if exists.
int compatibleWindowFlag =
mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
- mWindowAttributes.copyFrom(attrs);
+ mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
mWindowAttributes.flags |= compatibleWindowFlag;
if (newView) {
@@ -844,14 +846,17 @@
|| mNewSurfaceNeeded;
WindowManager.LayoutParams params = null;
+ int windowAttributesChanges = 0;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
surfaceChanged = true;
params = lp;
+ windowAttributesChanges = mWindowAttributesChangesFlag;
}
CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
params = lp;
+ windowAttributesChanges |= WindowManager.LayoutParams.BUFFER_CHANGED;
fullRedrawNeeded = true;
mLayoutRequested = true;
if (mLastInCompatMode) {
@@ -862,6 +867,9 @@
mLastInCompatMode = true;
}
}
+
+ mWindowAttributesChangesFlag = 0;
+
Rect frame = mWinFrame;
if (mFirst) {
fullRedrawNeeded = true;
@@ -1041,6 +1049,7 @@
|| attachInfo.mSystemUiVisibility != oldVis
|| attachInfo.mHasSystemUiListeners) {
params = lp;
+ windowAttributesChanges |= WindowManager.LayoutParams.BUFFER_CHANGED;
}
}
@@ -1066,6 +1075,7 @@
~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
resizeMode;
params = lp;
+ windowAttributesChanges |= WindowManager.LayoutParams.BUFFER_CHANGED;
}
}
}
@@ -1362,7 +1372,8 @@
}
}
- if (hwInitialized || ((windowShouldResize || params != null) &&
+ if (hwInitialized || ((windowShouldResize || (params != null &&
+ (windowAttributesChanges & WindowManager.LayoutParams.BUFFER_CHANGED) != 0)) &&
mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled())) {
mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
@@ -1608,11 +1619,13 @@
}
}
} else {
- // If we're not drawing, then we don't need to draw the transitions, either
- if (mPendingTransitions != null) {
+ // End any pending transitions on this non-visible window
+ if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
+ for (int i = 0; i < mPendingTransitions.size(); ++i) {
+ mPendingTransitions.get(i).endChangingAnimations();
+ }
mPendingTransitions.clear();
}
-
// We were supposed to report when we are done drawing. Since we canceled the
// draw, remember it here.
if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
@@ -1621,7 +1634,7 @@
if (fullRedrawNeeded) {
mFullRedrawNeeded = true;
}
-
+
if (viewVisibility == View.VISIBLE) {
// Try again
scheduleTraversals();
@@ -1637,6 +1650,7 @@
// Need to make sure we re-evaluate the window attributes next
// time around, to ensure the window has the correct format.
mWindowAttributesChanged = true;
+ mWindowAttributesChangesFlag = 0;
requestLayout();
}
}
@@ -4529,7 +4543,7 @@
predicate.init(accessibilityId);
View root = ViewRootImpl.this.mView;
View target = root.findViewByPredicate(predicate);
- if (target != null && target.isShown()) {
+ if (target != null && target.getVisibility() == View.VISIBLE) {
info = target.createAccessibilityNodeInfo();
}
} finally {
@@ -4572,7 +4586,7 @@
try {
View root = ViewRootImpl.this.mView;
View target = root.findViewById(viewId);
- if (target != null && target.isShown()) {
+ if (target != null && target.getVisibility() == View.VISIBLE) {
info = target.createAccessibilityNodeInfo();
}
} finally {
@@ -4623,14 +4637,14 @@
ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
foundViews.clear();
- View root;
+ View root = null;
if (accessibilityViewId != View.NO_ID) {
root = findViewByAccessibilityId(accessibilityViewId);
} else {
root = ViewRootImpl.this.mView;
}
- if (root == null || !root.isShown()) {
+ if (root == null || root.getVisibility() != View.VISIBLE) {
return;
}
@@ -4645,7 +4659,7 @@
final int viewCount = foundViews.size();
for (int i = 0; i < viewCount; i++) {
View foundView = foundViews.get(i);
- if (foundView.isShown()) {
+ if (foundView.getVisibility() == View.VISIBLE) {
infos.add(foundView.createAccessibilityNodeInfo());
}
}
@@ -4718,7 +4732,7 @@
private boolean performActionFocus(int accessibilityId) {
View target = findViewByAccessibilityId(accessibilityId);
- if (target == null) {
+ if (target == null || target.getVisibility() != View.VISIBLE) {
return false;
}
// Get out of touch mode since accessibility wants to move focus around.
@@ -4728,7 +4742,7 @@
private boolean performActionClearFocus(int accessibilityId) {
View target = findViewByAccessibilityId(accessibilityId);
- if (target == null) {
+ if (target == null || target.getVisibility() != View.VISIBLE) {
return false;
}
if (!target.isFocused()) {
@@ -4740,7 +4754,7 @@
private boolean performActionSelect(int accessibilityId) {
View target = findViewByAccessibilityId(accessibilityId);
- if (target == null) {
+ if (target == null || target.getVisibility() != View.VISIBLE) {
return false;
}
if (target.isSelected()) {
@@ -4752,7 +4766,7 @@
private boolean performActionClearSelection(int accessibilityId) {
View target = findViewByAccessibilityId(accessibilityId);
- if (target == null) {
+ if (target == null || target.getVisibility() != View.VISIBLE) {
return false;
}
if (!target.isSelected()) {
@@ -4769,18 +4783,21 @@
}
mFindByAccessibilityIdPredicate.init(accessibilityId);
View foundView = root.findViewByPredicate(mFindByAccessibilityIdPredicate);
- return (foundView != null && foundView.isShown()) ? foundView : null;
+ if (foundView == null || foundView.getVisibility() != View.VISIBLE) {
+ return null;
+ }
+ return foundView;
}
private final class FindByAccessibilitytIdPredicate implements Predicate<View> {
- public int mSerchedId;
+ public int mSearchedId;
public void init(int searchedId) {
- mSerchedId = searchedId;
+ mSearchedId = searchedId;
}
public boolean apply(View view) {
- return (view.getAccessibilityViewId() == mSerchedId);
+ return (view.getAccessibilityViewId() == mSearchedId);
}
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index fb31e7d..17a516c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -177,7 +177,14 @@
@ViewDebug.IntToString(from = TYPE_SYSTEM_ERROR, to = "TYPE_SYSTEM_ERROR"),
@ViewDebug.IntToString(from = TYPE_INPUT_METHOD, to = "TYPE_INPUT_METHOD"),
@ViewDebug.IntToString(from = TYPE_INPUT_METHOD_DIALOG, to = "TYPE_INPUT_METHOD_DIALOG"),
+ @ViewDebug.IntToString(from = TYPE_WALLPAPER, to = "TYPE_WALLPAPER"),
+ @ViewDebug.IntToString(from = TYPE_STATUS_BAR_PANEL, to = "TYPE_STATUS_BAR_PANEL"),
@ViewDebug.IntToString(from = TYPE_SECURE_SYSTEM_OVERLAY, to = "TYPE_SECURE_SYSTEM_OVERLAY"),
+ @ViewDebug.IntToString(from = TYPE_DRAG, to = "TYPE_DRAG"),
+ @ViewDebug.IntToString(from = TYPE_STATUS_BAR_SUB_PANEL, to = "TYPE_STATUS_BAR_SUB_PANEL"),
+ @ViewDebug.IntToString(from = TYPE_POINTER, to = "TYPE_POINTER"),
+ @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR, to = "TYPE_NAVIGATION_BAR"),
+ @ViewDebug.IntToString(from = TYPE_VOLUME_OVERLAY, to = "TYPE_VOLUME_OVERLAY"),
@ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS")
})
public int type;
@@ -1252,7 +1259,11 @@
public static final int INPUT_FEATURES_CHANGED = 1<<15;
/** {@hide} */
public static final int PRIVATE_FLAGS_CHANGED = 1<<16;
-
+ /** {@hide} */
+ public static final int BUFFER_CHANGED = 1<<17;
+ /** {@hide} */
+ public static final int EVERYTHING_CHANGED = 0xffffffff;
+
// internal buffer to backup/restore parameters under compatibility mode.
private int[] mCompatibilityParamsBackup = null;
@@ -1261,11 +1272,11 @@
if (width != o.width) {
width = o.width;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (height != o.height) {
height = o.height;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (x != o.x) {
x = o.x;
@@ -1277,19 +1288,19 @@
}
if (horizontalWeight != o.horizontalWeight) {
horizontalWeight = o.horizontalWeight;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (verticalWeight != o.verticalWeight) {
verticalWeight = o.verticalWeight;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (horizontalMargin != o.horizontalMargin) {
horizontalMargin = o.horizontalMargin;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (verticalMargin != o.verticalMargin) {
verticalMargin = o.verticalMargin;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (type != o.type) {
type = o.type;
@@ -1297,7 +1308,7 @@
}
if (flags != o.flags) {
flags = o.flags;
- changes |= FLAGS_CHANGED;
+ changes |= FLAGS_CHANGED | BUFFER_CHANGED;
}
if (privateFlags != o.privateFlags) {
privateFlags = o.privateFlags;
@@ -1309,11 +1320,11 @@
}
if (gravity != o.gravity) {
gravity = o.gravity;
- changes |= LAYOUT_CHANGED;
+ changes |= LAYOUT_CHANGED | BUFFER_CHANGED;
}
if (format != o.format) {
format = o.format;
- changes |= FORMAT_CHANGED;
+ changes |= FORMAT_CHANGED | BUFFER_CHANGED;
}
if (windowAnimations != o.windowAnimations) {
windowAnimations = o.windowAnimations;
@@ -1352,7 +1363,7 @@
if (screenOrientation != o.screenOrientation) {
screenOrientation = o.screenOrientation;
- changes |= SCREEN_ORIENTATION_CHANGED;
+ changes |= SCREEN_ORIENTATION_CHANGED | BUFFER_CHANGED;
}
if (systemUiVisibility != o.systemUiVisibility
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 071701e..25b980b 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -104,6 +104,7 @@
public void setSameThreadMessage(Message message) {
synchronized (mInstanceLock) {
mSameThreadMessage = message;
+ mInstanceLock.notifyAll();
}
}
@@ -125,7 +126,6 @@
Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
- handleSameThreadMessageIfNeeded();
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
finalizeAccessibilityNodeInfo(info, connection, windowScale);
@@ -142,7 +142,7 @@
* in the currently active window and starts from the root View in the window.
*
* @param connection A connection for interacting with the system.
- * @param id The id of the node.
+ * @param viewId The id of the view.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(
@@ -153,7 +153,6 @@
viewId, interactionId, this, Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
- handleSameThreadMessageIfNeeded();
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
finalizeAccessibilityNodeInfo(info, connection, windowScale);
@@ -182,7 +181,6 @@
text, interactionId, this, Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
- handleSameThreadMessageIfNeeded();
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
finalizeAccessibilityNodeInfos(infos, connection, windowScale);
@@ -217,7 +215,6 @@
Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
- handleSameThreadMessageIfNeeded();
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
finalizeAccessibilityNodeInfos(infos, connection, windowScale);
@@ -246,7 +243,6 @@
accessibilityWindowId, accessibilityViewId, action, interactionId, this,
Thread.currentThread().getId());
if (success) {
- handleSameThreadMessageIfNeeded();
return getPerformAccessibilityActionResult(interactionId);
}
} catch (RemoteException re) {
@@ -363,6 +359,11 @@
final long startTimeMillis = SystemClock.uptimeMillis();
while (true) {
try {
+ Message sameProcessMessage = getSameProcessMessageAndClear();
+ if (sameProcessMessage != null) {
+ sameProcessMessage.getTarget().handleMessage(sameProcessMessage);
+ }
+
if (mInteractionId == interactionId) {
return true;
}
@@ -402,17 +403,6 @@
}
/**
- * Handles the message stored if the interacted and interacting
- * threads are the same otherwise this is a NOP.
- */
- private void handleSameThreadMessageIfNeeded() {
- Message sameProcessMessage = getSameProcessMessageAndClear();
- if (sameProcessMessage != null) {
- sameProcessMessage.getTarget().handleMessage(sameProcessMessage);
- }
- }
-
- /**
* Finalize an {@link AccessibilityNodeInfo} before passing it to the client.
*
* @param info The info.
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 4f2542b..2cf8ea8 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.util.AttributeSet;
import android.graphics.RectF;
@@ -31,6 +32,22 @@
* If AnimationSet sets any properties that its children also set
* (for example, duration or fillBefore), the values of AnimationSet
* override the child values.
+ *
+ * <p>The way that AnimationSet inherits behavior from Animation is important to
+ * understand. Some of the Animation attributes applied to AnimationSet affect the
+ * AnimationSet itself, some are pushed down to the children, and some are ignored,
+ * as follows:
+ * <ul>
+ * <li>duration, repeatMode, fillBefore, fillAfter: These properties, when set
+ * on an AnimationSet object, will be pushed down to all child animations.</li>
+ * <li>repeatCount, fillEnabled: These properties are ignored for AnimationSet.</li>
+ * <li>startOffset, shareInterpolator: These properties apply to the AnimationSet itself.</li>
+ * </ul>
+ * Starting with {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH},
+ * the behavior of these properties is the same in XML resources and at runtime (prior to that
+ * release, the values set in XML were ignored for AnimationSet). That is, calling
+ * <code>setDuration(500)</code> on an AnimationSet has the same effect as declaring
+ * <code>android:duration="500"</code> in an XML resource for an AnimationSet object.</p>
*/
public class AnimationSet extends Animation {
private static final int PROPERTY_FILL_AFTER_MASK = 0x1;
@@ -69,7 +86,26 @@
setFlag(PROPERTY_SHARE_INTERPOLATOR_MASK,
a.getBoolean(com.android.internal.R.styleable.AnimationSet_shareInterpolator, true));
init();
-
+
+ if (context.getApplicationInfo().targetSdkVersion >=
+ Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ if (a.hasValue(com.android.internal.R.styleable.AnimationSet_duration)) {
+ mFlags |= PROPERTY_DURATION_MASK;
+ }
+ if (a.hasValue(com.android.internal.R.styleable.AnimationSet_fillBefore)) {
+ mFlags |= PROPERTY_FILL_BEFORE_MASK;
+ }
+ if (a.hasValue(com.android.internal.R.styleable.AnimationSet_fillAfter)) {
+ mFlags |= PROPERTY_FILL_AFTER_MASK;
+ }
+ if (a.hasValue(com.android.internal.R.styleable.AnimationSet_repeatMode)) {
+ mFlags |= PROPERTY_REPEAT_MODE_MASK;
+ }
+ if (a.hasValue(com.android.internal.R.styleable.AnimationSet_startOffset)) {
+ mFlags |= PROPERTY_START_OFFSET_MASK;
+ }
+ }
+
a.recycle();
}
@@ -112,7 +148,6 @@
private void init() {
mStartTime = 0;
- mDuration = 0;
}
@Override
@@ -171,6 +206,7 @@
public void setDuration(long durationMillis) {
mFlags |= PROPERTY_DURATION_MASK;
super.setDuration(durationMillis);
+ mLastEnd = mStartOffset + mDuration;
}
/**
@@ -192,12 +228,16 @@
mFlags |= PROPERTY_CHANGE_BOUNDS_MASK;
}
- if (mAnimations.size() == 1) {
- mDuration = a.getStartOffset() + a.getDuration();
+ if ((mFlags & PROPERTY_DURATION_MASK) == PROPERTY_DURATION_MASK) {
mLastEnd = mStartOffset + mDuration;
} else {
- mLastEnd = Math.max(mLastEnd, a.getStartOffset() + a.getDuration());
- mDuration = mLastEnd - mStartOffset;
+ if (mAnimations.size() == 1) {
+ mDuration = a.getStartOffset() + a.getDuration();
+ mLastEnd = mStartOffset + mDuration;
+ } else {
+ mLastEnd = Math.max(mLastEnd, a.getStartOffset() + a.getDuration());
+ mDuration = mLastEnd - mStartOffset;
+ }
}
mDirty = true;
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 5670432..34c9c29 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -63,7 +63,7 @@
*/
public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
boolean isAuxiliary) {
- this(nameId, iconId, locale, mode, extraValue, false, false);
+ this(nameId, iconId, locale, mode, extraValue, isAuxiliary, false);
}
/**
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index f89d490..309857d 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -43,6 +43,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
+import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charsets;
import java.security.PrivateKey;
@@ -421,9 +422,9 @@
final WebHistoryItem h = mCallbackProxy.getBackForwardList()
.getCurrentItem();
if (h != null) {
- String currentUrl = h.getUrl();
- if (currentUrl != null) {
- mDatabase.setFormData(currentUrl, data);
+ String url = WebTextView.urlForAutoCompleteData(h.getUrl());
+ if (url != null) {
+ mDatabase.setFormData(url, data);
}
}
}
@@ -1171,7 +1172,8 @@
X509Certificate cert = new X509CertImpl(cert_der);
SslCertificate sslCert = new SslCertificate(cert);
if (JniUtil.useChromiumHttpStack()) {
- ssl_error = SslError.SslErrorFromChromiumErrorCode(cert_error, sslCert, url);
+ ssl_error = SslError.SslErrorFromChromiumErrorCode(cert_error, sslCert,
+ new URL(url).getHost());
} else {
ssl_error = new SslError(cert_error, cert, url);
}
diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java
index 1b9a25e..97dc291 100644
--- a/core/java/android/webkit/HTML5VideoInline.java
+++ b/core/java/android/webkit/HTML5VideoInline.java
@@ -7,6 +7,7 @@
import android.webkit.HTML5VideoViewProxy;
import android.view.Surface;
import android.opengl.GLES20;
+import android.os.PowerManager;
/**
* @hide This is only used by the browser
@@ -51,6 +52,7 @@
public void prepareDataAndDisplayMode(HTML5VideoViewProxy proxy) {
super.prepareDataAndDisplayMode(proxy);
setFrameAvailableListener(proxy);
+ mPlayer.setWakeMode(proxy.getContext(), PowerManager.FULL_WAKE_LOCK);
}
// Pause the play and update the play/pause button
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 2a79caa..217ad7c 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -60,6 +60,8 @@
import android.widget.AutoCompleteTextView;
import android.widget.TextView;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.ArrayList;
import junit.framework.Assert;
@@ -1044,6 +1046,7 @@
break;
}
setHint(null);
+ setThreshold(1);
if (single) {
mWebView.requestLabel(mWebView.nativeFocusCandidateFramePointer(),
mNodePointer);
@@ -1077,4 +1080,16 @@
/* package */ void setAutoFillProfileIsSet(boolean autoFillProfileIsSet) {
mAutoFillProfileIsSet = autoFillProfileIsSet;
}
+
+ static String urlForAutoCompleteData(String urlString) {
+ // Remove any fragment or query string.
+ URL url = null;
+ try {
+ url = new URL(urlString);
+ } catch (MalformedURLException e) {
+ Log.e(LOGTAG, "Unable to parse URL "+url);
+ }
+
+ return url != null ? url.getProtocol() + "://" + url.getHost() + url.getPath() : null;
+ }
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5bb0ef2..47abbc2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -20,6 +20,7 @@
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ClipboardManager;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
@@ -382,6 +383,39 @@
}
}
+ private static class OnTrimMemoryListener implements ComponentCallbacks2 {
+ private static OnTrimMemoryListener sInstance = null;
+
+ static void init(Context c) {
+ if (sInstance == null) {
+ sInstance = new OnTrimMemoryListener(c.getApplicationContext());
+ }
+ }
+
+ private OnTrimMemoryListener(Context c) {
+ c.registerComponentCallbacks(this);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // Ignore
+ }
+
+ @Override
+ public void onLowMemory() {
+ // Ignore
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.d("WebView", "onTrimMemory: " + level);
+ }
+ WebView.nativeOnTrimMemory(level);
+ }
+
+ }
+
// A final CallbackProxy shared by WebViewCore and BrowserFrame.
private final CallbackProxy mCallbackProxy;
@@ -1194,6 +1228,8 @@
}
private void init() {
+ OnTrimMemoryListener.init(getContext());
+
setWillNotDraw(false);
setFocusable(true);
setFocusableInTouchMode(true);
@@ -4790,7 +4826,7 @@
public RequestFormData(String name, String url, Message msg,
boolean autoFillable, boolean autoComplete) {
mName = name;
- mUrl = url;
+ mUrl = WebTextView.urlForAutoCompleteData(url);
mUpdateMessage = msg;
mAutoFillable = autoFillable;
mAutoComplete = autoComplete;
@@ -9404,4 +9440,8 @@
native boolean nativeSetProperty(String key, String value);
native String nativeGetProperty(String key);
private native void nativeGetTextSelectionRegion(Region region);
+ /**
+ * See {@link ComponentCallbacks2} for the trim levels and descriptions
+ */
+ private static native void nativeOnTrimMemory(int level);
}
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 9fea506..bc44521 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -663,6 +663,17 @@
}
}
+ /**
+ * Gets the history size.
+ *
+ * @return The history size.
+ */
+ public int getHistorySize() {
+ synchronized (mInstanceLock) {
+ return mHistoricalRecords.size();
+ }
+ }
+
@Override
protected void finalize() throws Throwable {
super.finalize();
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index fcc7938..312303d 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -28,6 +28,7 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -76,6 +77,11 @@
private final LinearLayout mActivityChooserContent;
/**
+ * Stores the background drawable to allow hiding and latter showing.
+ */
+ private final Drawable mActivityChooserContentBackground;
+
+ /**
* The expand activities action button;
*/
private final FrameLayout mExpandActivityOverflowButton;
@@ -194,12 +200,15 @@
Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
R.styleable.ActivityChooserView_expandActivityOverflowButtonDrawable);
+ attributesArray.recycle();
+
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.activity_chooser_view, this, true);
mCallbacks = new Callbacks();
mActivityChooserContent = (LinearLayout) findViewById(R.id.activity_chooser_view_content);
+ mActivityChooserContentBackground = mActivityChooserContent.getBackground();
mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
mDefaultActivityButton.setOnClickListener(mCallbacks);
@@ -217,7 +226,7 @@
@Override
public void onChanged() {
super.onChanged();
- updateButtons();
+ updateAppearance();
}
});
@@ -352,9 +361,16 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- mActivityChooserContent.measure(widthMeasureSpec, heightMeasureSpec);
- setMeasuredDimension(mActivityChooserContent.getMeasuredWidth(),
- mActivityChooserContent.getMeasuredHeight());
+ View child = mActivityChooserContent;
+ // If the default action is not visible we want to be as tall as the
+ // ActionBar so if this widget is used in the latter it will look as
+ // a normal action button.
+ if (mDefaultActivityButton.getVisibility() != VISIBLE) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+ MeasureSpec.EXACTLY);
+ }
+ measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
}
@Override
@@ -367,11 +383,6 @@
}
}
- @Override
- protected void onDraw(Canvas canvas) {
- mActivityChooserContent.onDraw(canvas);
- }
-
public ActivityChooserModel getDataModel() {
return mAdapter.getDataModel();
}
@@ -417,21 +428,29 @@
/**
* Updates the buttons state.
*/
- private void updateButtons() {
+ private void updateAppearance() {
+ // Expand overflow button.
+ if (mAdapter.getCount() > 0) {
+ mExpandActivityOverflowButton.setEnabled(true);
+ } else {
+ mExpandActivityOverflowButton.setEnabled(false);
+ }
+ // Default activity button.
final int activityCount = mAdapter.getActivityCount();
- if (activityCount > 0) {
+ final int historySize = mAdapter.getHistorySize();
+ if (activityCount > 0 && historySize > 0) {
mDefaultActivityButton.setVisibility(VISIBLE);
- if (mAdapter.getCount() > 0) {
- mExpandActivityOverflowButton.setEnabled(true);
- } else {
- mExpandActivityOverflowButton.setEnabled(false);
- }
ResolveInfo activity = mAdapter.getDefaultActivity();
PackageManager packageManager = mContext.getPackageManager();
mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
} else {
- mDefaultActivityButton.setVisibility(View.INVISIBLE);
- mExpandActivityOverflowButton.setEnabled(false);
+ mDefaultActivityButton.setVisibility(View.GONE);
+ }
+ // Activity chooser content.
+ if (mDefaultActivityButton.getVisibility() == VISIBLE) {
+ mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
+ } else {
+ mActivityChooserContent.setBackgroundDrawable(null);
}
}
@@ -678,6 +697,10 @@
return mDataModel.getActivityCount();
}
+ public int getHistorySize() {
+ return mDataModel.getHistorySize();
+ }
+
public int getMaxActivityCount() {
return mMaxActivityCount;
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index b945038..2d10bbe 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -886,9 +886,11 @@
event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
- // We first get a chance to populate the event.
- onPopulateAccessibilityEvent(event);
-
+ View selectedView = getSelectedView();
+ if (selectedView != null && selectedView.getVisibility() == VISIBLE) {
+ // We first get a chance to populate the event.
+ onPopulateAccessibilityEvent(event);
+ }
return false;
}
@@ -896,10 +898,7 @@
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
// We send selection events only from AdapterView to avoid
// generation of such event for each child.
- View selectedView = getSelectedView();
- if (selectedView != null) {
- selectedView.dispatchPopulateAccessibilityEvent(event);
- }
+ getSelectedView().dispatchPopulateAccessibilityEvent(event);
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 3b67f44..5077be6 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -31,6 +31,7 @@
import android.view.LayoutInflater;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.EditorInfo;
import android.widget.NumberPicker.OnValueChangeListener;
import com.android.internal.R;
@@ -81,10 +82,10 @@
private static final boolean DEFAULT_ENABLED_STATE = true;
- private final NumberPicker mDaySpinner;
-
private final LinearLayout mSpinners;
+ private final NumberPicker mDaySpinner;
+
private final NumberPicker mMonthSpinner;
private final NumberPicker mYearSpinner;
@@ -481,16 +482,20 @@
private void reorderSpinners() {
mSpinners.removeAllViews();
char[] order = DateFormat.getDateFormatOrder(getContext());
- for (int i = 0; i < order.length; i++) {
+ final int spinnerCount = order.length;
+ for (int i = 0; i < spinnerCount; i++) {
switch (order[i]) {
case DateFormat.DATE:
mSpinners.addView(mDaySpinner);
+ setImeOptions(mDaySpinner, spinnerCount, i);
break;
case DateFormat.MONTH:
mSpinners.addView(mMonthSpinner);
+ setImeOptions(mMonthSpinner, spinnerCount, i);
break;
case DateFormat.YEAR:
mSpinners.addView(mYearSpinner);
+ setImeOptions(mYearSpinner, spinnerCount, i);
break;
default:
throw new IllegalArgumentException();
@@ -669,6 +674,42 @@
}
/**
+ * Sets the IME options for a spinner based on its ordering.
+ *
+ * @param spinner The spinner.
+ * @param spinnerCount The total spinner count.
+ * @param spinnerIndex The index of the given spinner.
+ */
+ private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
+ final int imeOptions;
+ if (spinnerIndex < spinnerCount - 1) {
+ imeOptions = EditorInfo.IME_ACTION_NEXT;
+ } else {
+ imeOptions = EditorInfo.IME_ACTION_DONE;
+ }
+ TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input);
+ input.setImeOptions(imeOptions);
+ }
+
+ private void setContentDescriptions() {
+ // Day
+ String text = mContext.getString(R.string.date_picker_increment_day_button);
+ mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.date_picker_decrement_day_button);
+ mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
+ // Month
+ text = mContext.getString(R.string.date_picker_increment_month_button);
+ mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.date_picker_decrement_month_button);
+ mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
+ // Year
+ text = mContext.getString(R.string.date_picker_increment_year_button);
+ mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.date_picker_decrement_year_button);
+ mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
+ }
+
+ /**
* Class for managing state storing/restoring.
*/
private static class SavedState extends BaseSavedState {
@@ -720,22 +761,4 @@
}
};
}
-
- private void setContentDescriptions() {
- // Day
- String text = mContext.getString(R.string.date_picker_increment_day_button);
- mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
- text = mContext.getString(R.string.date_picker_decrement_day_button);
- mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
- // Month
- text = mContext.getString(R.string.date_picker_increment_month_button);
- mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
- text = mContext.getString(R.string.date_picker_decrement_month_button);
- mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
- // Year
- text = mContext.getString(R.string.date_picker_increment_year_button);
- mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
- text = mContext.getString(R.string.date_picker_decrement_year_button);
- mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
- }
}
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 0b0b812..74a57b0 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -250,6 +250,27 @@
return mForeground;
}
+ private int getPaddingLeftWithForeground() {
+ return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
+ mPaddingLeft + mForegroundPaddingLeft;
+ }
+
+ private int getPaddingRightWithForeground() {
+ return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) :
+ mPaddingRight + mForegroundPaddingRight;
+ }
+
+ private int getPaddingTopWithForeground() {
+ return mForegroundInPadding ? Math.max(mPaddingTop, mForegroundPaddingTop) :
+ mPaddingTop + mForegroundPaddingTop;
+ }
+
+ private int getPaddingBottomWithForeground() {
+ return mForegroundInPadding ? Math.max(mPaddingBottom, mForegroundPaddingBottom) :
+ mPaddingBottom + mForegroundPaddingBottom;
+ }
+
+
/**
* {@inheritDoc}
*/
@@ -286,8 +307,8 @@
}
// Account for padding too
- maxWidth += mPaddingLeft + mPaddingRight + mForegroundPaddingLeft + mForegroundPaddingRight;
- maxHeight += mPaddingTop + mPaddingBottom + mForegroundPaddingTop + mForegroundPaddingBottom;
+ maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
+ maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
@@ -315,21 +336,25 @@
if (lp.width == LayoutParams.MATCH_PARENT) {
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -
- mPaddingLeft - mPaddingRight - lp.leftMargin - lp.rightMargin,
+ getPaddingLeftWithForeground() - getPaddingRightWithForeground() -
+ lp.leftMargin - lp.rightMargin,
MeasureSpec.EXACTLY);
} else {
childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
- mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
+ getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
+ lp.leftMargin + lp.rightMargin,
lp.width);
}
if (lp.height == LayoutParams.MATCH_PARENT) {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -
- mPaddingTop - mPaddingBottom - lp.topMargin - lp.bottomMargin,
+ getPaddingTopWithForeground() - getPaddingBottomWithForeground() -
+ lp.topMargin - lp.bottomMargin,
MeasureSpec.EXACTLY);
} else {
childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
- mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
+ getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
+ lp.topMargin + lp.bottomMargin,
lp.height);
}
@@ -345,11 +370,11 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int count = getChildCount();
- final int parentLeft = mPaddingLeft + mForegroundPaddingLeft;
- final int parentRight = right - left - mPaddingRight - mForegroundPaddingRight;
+ final int parentLeft = getPaddingLeftWithForeground();
+ final int parentRight = right - left - getPaddingRightWithForeground();
- final int parentTop = mPaddingTop + mForegroundPaddingTop;
- final int parentBottom = bottom - top - mPaddingBottom - mForegroundPaddingBottom;
+ final int parentTop = getPaddingTopWithForeground();
+ final int parentBottom = bottom - top - getPaddingBottomWithForeground();
mForegroundBoundsChanged = true;
@@ -465,23 +490,42 @@
}
/**
- * Determines whether to measure all children or just those in
- * the VISIBLE or INVISIBLE state when measuring. Defaults to false.
+ * Sets whether to consider all children, or just those in
+ * the VISIBLE or INVISIBLE state, when measuring. Defaults to false.
+ *
* @param measureAll true to consider children marked GONE, false otherwise.
* Default value is false.
- *
+ *
* @attr ref android.R.styleable#FrameLayout_measureAllChildren
*/
@android.view.RemotableViewMethod
public void setMeasureAllChildren(boolean measureAll) {
mMeasureAllChildren = measureAll;
}
-
+
/**
- * Determines whether to measure all children or just those in
- * the VISIBLE or INVISIBLE state when measuring.
+ * Determines whether all children, or just those in the VISIBLE or
+ * INVISIBLE state, are considered when measuring.
+ *
+ * @return Whether all children are considered when measuring.
+ *
+ * @deprecated This method is deprecated in favor of
+ * {@link #getMeasureAllChildren() getMeasureAllChildren()}, which was
+ * renamed for consistency with
+ * {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()}.
*/
+ @Deprecated
public boolean getConsiderGoneChildrenWhenMeasuring() {
+ return getMeasureAllChildren();
+ }
+
+ /**
+ * Determines whether all children, or just those in the VISIBLE or
+ * INVISIBLE state, are considered when measuring.
+ *
+ * @return Whether all children are considered when measuring.
+ */
+ public boolean getMeasureAllChildren() {
return mMeasureAllChildren;
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 35e48f2..5345fa4 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -33,7 +33,6 @@
import android.graphics.Rect;
import android.graphics.Paint.Align;
import android.graphics.drawable.Drawable;
-import android.os.SystemClock;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
@@ -517,7 +516,10 @@
mInputText = (EditText) findViewById(R.id.numberpicker_input);
mInputText.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
- if (!hasFocus) {
+ if (hasFocus) {
+ mInputText.selectAll();
+ } else {
+ mInputText.setSelection(0, 0);
validateInputTextView(v);
}
}
@@ -687,7 +689,6 @@
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mInputText, 0);
- mInputText.setSelection(0, mInputText.getText().length());
return true;
}
VelocityTracker velocityTracker = mVelocityTracker;
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a5cf62e..6edfd59 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -961,7 +961,8 @@
}
for (View view : mTopToBottomLeftToRightSet) {
- if (view.dispatchPopulateAccessibilityEvent(event)) {
+ if (view.getVisibility() == View.VISIBLE
+ && view.dispatchPopulateAccessibilityEvent(event)) {
mTopToBottomLeftToRightSet.clear();
return true;
}
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 4b08f2d..0cd14d0 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -148,14 +148,23 @@
private int mFramePadding;
private final Rect stackInvalidateRect = new Rect();
+ /**
+ * {@inheritDoc}
+ */
public StackView(Context context) {
this(context, null);
}
+ /**
+ * {@inheritDoc}
+ */
public StackView(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.stackViewStyle);
}
+ /**
+ * {@inheritDoc}
+ */
public StackView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 9afb625..191c4ca 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -405,7 +405,10 @@
onPopulateAccessibilityEvent(event);
// Dispatch only to the selected tab.
if (mSelectedTab != -1) {
- return getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event);
+ View tabView = getChildTabViewAt(mSelectedTab);
+ if (tabView != null && tabView.getVisibility() == VISIBLE) {
+ return tabView.dispatchPopulateAccessibilityEvent(event);
+ }
}
return false;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3f68ce3..b948114 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3726,19 +3726,19 @@
// instead turning this into the normal enter key codes that an
// app may be expecting.
if (actionCode == EditorInfo.IME_ACTION_NEXT) {
- View v = focusSearch(FOCUS_DOWN);
+ View v = focusSearch(FOCUS_FORWARD);
if (v != null) {
- if (!v.requestFocus(FOCUS_DOWN)) {
+ if (!v.requestFocus(FOCUS_FORWARD)) {
throw new IllegalStateException("focus search returned a view " +
"that wasn't able to take focus!");
}
}
return;
-
+
} else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
- View v = focusSearch(FOCUS_UP);
+ View v = focusSearch(FOCUS_BACKWARD);
if (v != null) {
- if (!v.requestFocus(FOCUS_UP)) {
+ if (!v.requestFocus(FOCUS_BACKWARD)) {
throw new IllegalStateException("focus search returned a view " +
"that wasn't able to take focus!");
}
@@ -3750,10 +3750,11 @@
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
+ clearFocus();
return;
}
}
-
+
Handler h = getHandler();
if (h != null) {
long eventTime = SystemClock.uptimeMillis();
@@ -4050,16 +4051,9 @@
int wid = tv.getPaddingLeft() + tv.getPaddingRight();
int ht = tv.getPaddingTop() + tv.getPaddingBottom();
- /*
- * Figure out how big the text would be if we laid it out to the
- * full width of this view minus the border.
- */
- int cap = getWidth() - wid;
- if (cap < 0) {
- cap = 200; // We must not be measured yet -- setFrame() will fix it.
- }
-
- Layout l = new StaticLayout(text, tv.getPaint(), cap,
+ int defaultWidthInPixels = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.textview_error_popup_default_width);
+ Layout l = new StaticLayout(text, tv.getPaint(), defaultWidthInPixels,
Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
float max = 0;
for (int i = 0; i < l.getLineCount(); i++) {
@@ -4067,7 +4061,8 @@
}
/*
- * Now set the popup size to be big enough for the text plus the border.
+ * Now set the popup size to be big enough for the text plus the border capped
+ * to DEFAULT_MAX_POPUP_WIDTH
*/
pop.setWidth(wid + (int) Math.ceil(max));
pop.setHeight(ht + l.getHeight());
@@ -5432,8 +5427,8 @@
if (mMovement != null && mText instanceof Editable
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
+ viewClicked(imm);
if (imm != null) {
- imm.viewClicked(this);
imm.showSoftInput(this, 0);
}
}
@@ -5746,7 +5741,7 @@
MetaKeyKeyListener.stopSelecting(this, sp);
}
}
-
+
/**
* @hide
*/
@@ -5754,10 +5749,12 @@
if (mInputMethodState != null) {
mInputMethodState.mExtracting = req;
}
- // This stops a possible text selection mode. Maybe not intended.
+ // This would stop a possible selection mode, but no such mode is started in case
+ // extracted mode will start. Some text is selected though, and will trigger an action mode
+ // in the extracted view.
hideControllers();
}
-
+
/**
* Called by the framework in response to a text completion from
* the current input method, provided by it calling
@@ -7591,7 +7588,9 @@
// Hide the controllers if the amount of content changed
if (before != after) {
- hideControllers();
+ // We do not hide the span controllers, as they can be added when a new text is
+ // inserted into the text view
+ hideCursorControllers();
}
}
@@ -7799,20 +7798,23 @@
* Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
* pop-up should be displayed.
*/
- private class EditTextShortcutController {
+ private class EasyEditSpanController {
- private EditTextShortcutPopupWindow mPopupWindow;
+ private static final int DISPLAY_TIMEOUT_MS = 3000; // 3 secs
- private EasyEditSpan mEditTextShortcutSpan;
+ private EasyEditPopupWindow mPopupWindow;
+
+ private EasyEditSpan mEasyEditSpan;
+
+ private Runnable mHidePopup;
private void hide() {
- if (mEditTextShortcutSpan != null) {
+ if (mPopupWindow != null) {
mPopupWindow.hide();
- if (mText instanceof Spannable) {
- ((Spannable) mText).removeSpan(mEditTextShortcutSpan);
- }
- mEditTextShortcutSpan = null;
+ TextView.this.removeCallbacks(mHidePopup);
}
+ removeSpans(mText);
+ mEasyEditSpan = null;
}
/**
@@ -7822,43 +7824,111 @@
* as the notifications are not sent when a spannable (with spans) is inserted.
*/
public void onTextChange(CharSequence buffer) {
- if (mEditTextShortcutSpan != null) {
- hide();
+ adjustSpans(mText);
+
+ if (getWindowVisibility() != View.VISIBLE) {
+ // The window is not visible yet, ignore the text change.
+ return;
}
+ if (mLayout == null) {
+ // The view has not been layout yet, ignore the text change
+ return;
+ }
+
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (!(TextView.this instanceof ExtractEditText)
+ && imm != null && imm.isFullscreenMode()) {
+ // The input is in extract mode. We do not have to handle the easy edit in the
+ // original TextView, as the ExtractEditText will do
+ return;
+ }
+
+ // Remove the current easy edit span, as the text changed, and remove the pop-up
+ // (if any)
+ if (mEasyEditSpan != null) {
+ if (mText instanceof Spannable) {
+ ((Spannable) mText).removeSpan(mEasyEditSpan);
+ }
+ mEasyEditSpan = null;
+ }
+ if (mPopupWindow != null && mPopupWindow.isShowing()) {
+ mPopupWindow.hide();
+ }
+
+ // Display the new easy edit span (if any).
if (buffer instanceof Spanned) {
- mEditTextShortcutSpan = getSpan((Spanned) buffer);
- if (mEditTextShortcutSpan != null) {
+ mEasyEditSpan = getSpan((Spanned) buffer);
+ if (mEasyEditSpan != null) {
if (mPopupWindow == null) {
- mPopupWindow = new EditTextShortcutPopupWindow();
+ mPopupWindow = new EasyEditPopupWindow();
+ mHidePopup = new Runnable() {
+ @Override
+ public void run() {
+ hide();
+ }
+ };
}
- mPopupWindow.show(mEditTextShortcutSpan);
+ mPopupWindow.show(mEasyEditSpan);
+ TextView.this.removeCallbacks(mHidePopup);
+ TextView.this.postDelayed(mHidePopup, DISPLAY_TIMEOUT_MS);
+ }
+ }
+ }
+
+ /**
+ * Adjusts the spans by removing all of them except the last one.
+ */
+ private void adjustSpans(CharSequence buffer) {
+ // This method enforces that only one easy edit span is attached to the text.
+ // A better way to enforce this would be to listen for onSpanAdded, but this method
+ // cannot be used in this scenario as no notification is triggered when a text with
+ // spans is inserted into a text.
+ if (buffer instanceof Spannable) {
+ Spannable spannable = (Spannable) buffer;
+ EasyEditSpan[] spans = spannable.getSpans(0, spannable.length(),
+ EasyEditSpan.class);
+ for (int i = 0; i < spans.length - 1; i++) {
+ spannable.removeSpan(spans[i]);
+ }
+ }
+ }
+
+ /**
+ * Removes all the {@link EasyEditSpan} currently attached.
+ */
+ private void removeSpans(CharSequence buffer) {
+ if (buffer instanceof Spannable) {
+ Spannable spannable = (Spannable) buffer;
+ EasyEditSpan[] spans = spannable.getSpans(0, spannable.length(),
+ EasyEditSpan.class);
+ for (int i = 0; i < spans.length; i++) {
+ spannable.removeSpan(spans[i]);
}
}
}
private EasyEditSpan getSpan(Spanned spanned) {
- EasyEditSpan[] inputMethodSpans = spanned.getSpans(0, spanned.length(),
+ EasyEditSpan[] easyEditSpans = spanned.getSpans(0, spanned.length(),
EasyEditSpan.class);
-
- if (inputMethodSpans.length == 0) {
+ if (easyEditSpans.length == 0) {
return null;
} else {
- return inputMethodSpans[0];
+ return easyEditSpans[0];
}
}
}
/**
* Displays the actions associated to an {@link EasyEditSpan}. The pop-up is controlled
- * by {@link EditTextShortcutController}.
+ * by {@link EasyEditSpanController}.
*/
- private class EditTextShortcutPopupWindow extends PinnedPopupWindow
+ private class EasyEditPopupWindow extends PinnedPopupWindow
implements OnClickListener {
private static final int POPUP_TEXT_LAYOUT =
com.android.internal.R.layout.text_edit_action_popup_text;
private TextView mDeleteTextView;
- private EasyEditSpan mEditTextShortcutSpan;
+ private EasyEditSpan mEasyEditSpan;
@Override
protected void createPopupWindow() {
@@ -7889,8 +7959,8 @@
mContentView.addView(mDeleteTextView);
}
- public void show(EasyEditSpan inputMethodSpan) {
- mEditTextShortcutSpan = inputMethodSpan;
+ public void show(EasyEditSpan easyEditSpan) {
+ mEasyEditSpan = easyEditSpan;
super.show();
}
@@ -7903,8 +7973,8 @@
private void deleteText() {
Editable editable = (Editable) mText;
- int start = editable.getSpanStart(mEditTextShortcutSpan);
- int end = editable.getSpanEnd(mEditTextShortcutSpan);
+ int start = editable.getSpanStart(mEasyEditSpan);
+ int end = editable.getSpanEnd(mEasyEditSpan);
if (start >= 0 && end >= 0) {
editable.delete(start, end);
}
@@ -7914,7 +7984,7 @@
protected int getTextOffset() {
// Place the pop-up at the end of the span
Editable editable = (Editable) mText;
- return editable.getSpanEnd(mEditTextShortcutSpan);
+ return editable.getSpanEnd(mEasyEditSpan);
}
@Override
@@ -7933,10 +8003,10 @@
private CharSequence mBeforeText;
- private EditTextShortcutController mEditTextShortcutController;
+ private EasyEditSpanController mEasyEditSpanController;
private ChangeWatcher() {
- mEditTextShortcutController = new EditTextShortcutController();
+ mEasyEditSpanController = new EasyEditSpanController();
}
public void beforeTextChanged(CharSequence buffer, int start,
@@ -7959,7 +8029,7 @@
+ " before=" + before + " after=" + after + ": " + buffer);
TextView.this.handleTextChanged(buffer, start, before, after);
- mEditTextShortcutController.onTextChange(buffer);
+ mEasyEditSpanController.onTextChange(buffer);
if (AccessibilityManager.getInstance(mContext).isEnabled() &&
(isFocused() || isSelected() && isShown())) {
@@ -7997,7 +8067,7 @@
}
private void hideControllers() {
- mEditTextShortcutController.hide();
+ mEasyEditSpanController.hide();
}
}
@@ -8273,9 +8343,7 @@
if (touchIsFinished && (isTextEditable() || mTextIsSelectable)) {
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- imm.viewClicked(this);
- }
+ viewClicked(imm);
if (!mTextIsSelectable) {
handled |= imm != null && imm.showSoftInput(this, 0);
}
@@ -9155,21 +9223,23 @@
@Override
public boolean performLongClick() {
+ boolean handled = false;
+ boolean vibrate = true;
+
if (super.performLongClick()) {
mDiscardNextActionUp = true;
- return true;
+ handled = true;
}
- boolean handled = false;
-
// Long press in empty space moves cursor and shows the Paste affordance if available.
- if (!isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
+ if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
mInsertionControllerEnabled) {
final int offset = getOffsetForPosition(mLastDownPositionX, mLastDownPositionY);
stopSelectionActionMode();
Selection.setSelection((Spannable) mText, offset);
getInsertionController().showWithActionPopup();
handled = true;
+ vibrate = false;
}
if (!handled && mSelectionActionMode != null) {
@@ -9191,10 +9261,15 @@
}
// Start a new selection
- handled |= !handled && startSelectionActionMode();
+ if (!handled) {
+ handled = startSelectionActionMode();
+ }
+
+ if (vibrate) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
if (handled) {
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mDiscardNextActionUp = true;
}
@@ -9236,8 +9311,9 @@
}
private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
- // 3 handles, 2 ActionPopup (suggestionsPopup first hides the others)
- private final int MAXIMUM_NUMBER_OF_LISTENERS = 5;
+ // 3 handles
+ // 3 ActionPopup [replace, suggestion, easyedit] (suggestionsPopup first hides the others)
+ private final int MAXIMUM_NUMBER_OF_LISTENERS = 6;
private TextViewPositionListener[] mPositionListeners =
new TextViewPositionListener[MAXIMUM_NUMBER_OF_LISTENERS];
private boolean mCanMove[] = new boolean[MAXIMUM_NUMBER_OF_LISTENERS];
@@ -9467,10 +9543,6 @@
private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
- private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
- private WordIterator mSuggestionWordIterator;
- private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
- [(int) (AVERAGE_HIGHLIGHTS_PER_SUGGESTION * MAX_NUMBER_SUGGESTIONS)];
private SuggestionInfo[] mSuggestionInfos;
private int mNumberOfSuggestions;
private boolean mCursorWasVisibleBeforeSuggestions;
@@ -9485,8 +9557,10 @@
public void dismiss() {
super.dismiss();
- if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
- ((Editable) mText).removeSpan(mSuggestionRangeSpan);
+ TextView.this.getPositionListener().removeSubscriber(SuggestionsPopupWindow.this);
+
+ if ((mText instanceof Spannable)) {
+ ((Spannable) mText).removeSpan(mSuggestionRangeSpan);
}
setCursorVisible(mCursorWasVisibleBeforeSuggestions);
@@ -9497,10 +9571,6 @@
}
public SuggestionsPopupWindow() {
- for (int i = 0; i < mHighlightSpans.length; i++) {
- mHighlightSpans[i] = new TextAppearanceSpan(mContext,
- android.R.style.TextAppearance_SuggestionHighlight);
- }
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
}
@@ -9534,6 +9604,8 @@
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
int suggestionIndex; // the index of the suggestion inside suggestionSpan
SpannableStringBuilder text = new SpannableStringBuilder();
+ TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext,
+ android.R.style.TextAppearance_SuggestionHighlight);
void removeMisspelledFlag() {
int suggestionSpanFlags = suggestionSpan.getFlags();
@@ -9672,7 +9744,7 @@
}
private boolean updateSuggestions() {
- Spannable spannable = (Spannable)TextView.this.mText;
+ Spannable spannable = (Spannable) TextView.this.mText;
SuggestionSpan[] suggestionSpans = getSuggestionSpans();
final int nbSpans = suggestionSpans.length;
@@ -9682,6 +9754,7 @@
int spanUnionEnd = 0;
SuggestionSpan misspelledSpan = null;
+ int underlineColor = 0;
for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
SuggestionSpan suggestionSpan = suggestionSpans[spanIndex];
@@ -9694,6 +9767,9 @@
misspelledSpan = suggestionSpan;
}
+ // The first span dictates the background color of the highlighted text
+ if (spanIndex == 0) underlineColor = suggestionSpan.getUnderlineColor();
+
String[] suggestions = suggestionSpan.getSuggestions();
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
@@ -9736,9 +9812,17 @@
if (mNumberOfSuggestions == 0) return false;
- if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
- new SuggestionRangeSpan(mHighlightColor);
- ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
+ if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
+ if (underlineColor == 0) {
+ // Fallback on the default highlight color when the first span does not provide one
+ mSuggestionRangeSpan.setBackgroundColor(mHighlightColor);
+ } else {
+ final float BACKGROUND_TRANSPARENCY = 0.3f;
+ final int newAlpha = (int) (Color.alpha(underlineColor) * BACKGROUND_TRANSPARENCY);
+ mSuggestionRangeSpan.setBackgroundColor(
+ (underlineColor & 0x00FFFFFF) + (newAlpha << 24));
+ }
+ spannable.setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mSuggestionsAdapter.notifyDataSetChanged();
@@ -9746,152 +9830,23 @@
return true;
}
- private long[] getWordLimits(CharSequence text) {
- // TODO locale for mSuggestionWordIterator
- if (mSuggestionWordIterator == null) mSuggestionWordIterator = new WordIterator();
- mSuggestionWordIterator.setCharSequence(text);
-
- // First pass will simply count the number of words to be able to create an array
- // Not too expensive since previous break positions are cached by the BreakIterator
- int nbWords = 0;
- int position = mSuggestionWordIterator.following(0);
- while (position != BreakIterator.DONE) {
- nbWords++;
- position = mSuggestionWordIterator.following(position);
- }
-
- int index = 0;
- long[] result = new long[nbWords];
-
- position = mSuggestionWordIterator.following(0);
- while (position != BreakIterator.DONE) {
- int wordStart = mSuggestionWordIterator.getBeginning(position);
- result[index++] = packRangeInLong(wordStart, position);
- position = mSuggestionWordIterator.following(position);
- }
-
- return result;
- }
-
- private TextAppearanceSpan highlightSpan(int index) {
- final int length = mHighlightSpans.length;
- if (index < length) {
- return mHighlightSpans[index];
- }
-
- // Assumes indexes are requested in sequence: simply append one more item
- TextAppearanceSpan[] newArray = new TextAppearanceSpan[length + 1];
- System.arraycopy(mHighlightSpans, 0, newArray, 0, length);
- TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext,
- android.R.style.TextAppearance_SuggestionHighlight);
- newArray[length] = highlightSpan;
- mHighlightSpans = newArray;
- return highlightSpan;
- }
-
- private void highlightTextDifferences(SuggestionInfo suggestionInfo,
- int unionStart, int unionEnd) {
+ private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
+ int unionEnd) {
final int spanStart = suggestionInfo.spanStart;
final int spanEnd = suggestionInfo.spanEnd;
- // Remove all text formating by converting to Strings
- final String text = suggestionInfo.text.toString();
- final String sourceText = mText.subSequence(spanStart, spanEnd).toString();
+ // Adjust the start/end of the suggestion span
+ suggestionInfo.suggestionStart = spanStart - unionStart;
+ suggestionInfo.suggestionEnd = suggestionInfo.suggestionStart
+ + suggestionInfo.text.length();
+
+ suggestionInfo.text.clearSpans();
+ suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0,
+ suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- long[] sourceWordLimits = getWordLimits(sourceText);
- long[] wordLimits = getWordLimits(text);
-
- SpannableStringBuilder ssb = new SpannableStringBuilder();
- // span [spanStart, spanEnd] is included in union [spanUnionStart, int spanUnionEnd]
- // The final result is made of 3 parts: the text before, between and after the span
- // This is the text before, provided for context
- ssb.append(mText.subSequence(unionStart, spanStart).toString());
-
- // shift is used to offset spans positions wrt span's beginning
- final int shift = spanStart - unionStart;
- suggestionInfo.suggestionStart = shift;
- suggestionInfo.suggestionEnd = shift + text.length();
-
- // This is the actual suggestion text, which will be highlighted by the following code
- ssb.append(text);
-
- String[] words = new String[wordLimits.length];
- for (int i = 0; i < wordLimits.length; i++) {
- int wordStart = extractRangeStartFromLong(wordLimits[i]);
- int wordEnd = extractRangeEndFromLong(wordLimits[i]);
- words[i] = text.substring(wordStart, wordEnd);
- }
-
- // Highlighted word algorithm is based on word matching between source and text
- // Matching words are found from left to right. TODO: change for RTL languages
- // Characters between matching words are highlighted
- int previousCommonWordIndex = -1;
- int nbHighlightSpans = 0;
- for (int i = 0; i < sourceWordLimits.length; i++) {
- int wordStart = extractRangeStartFromLong(sourceWordLimits[i]);
- int wordEnd = extractRangeEndFromLong(sourceWordLimits[i]);
- String sourceWord = sourceText.substring(wordStart, wordEnd);
-
- for (int j = previousCommonWordIndex + 1; j < words.length; j++) {
- if (sourceWord.equals(words[j])) {
- if (j != previousCommonWordIndex + 1) {
- int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 :
- extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
- int lastDifferentPosition = extractRangeStartFromLong(wordLimits[j]);
- ssb.setSpan(highlightSpan(nbHighlightSpans++),
- shift + firstDifferentPosition, shift + lastDifferentPosition,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- } else {
- // Compare characters between words
- int previousSourceWordEnd = i == 0 ? 0 :
- extractRangeEndFromLong(sourceWordLimits[i - 1]);
- int sourceWordStart = extractRangeStartFromLong(sourceWordLimits[i]);
- String sourceSpaces = sourceText.substring(previousSourceWordEnd,
- sourceWordStart);
-
- int previousWordEnd = j == 0 ? 0 :
- extractRangeEndFromLong(wordLimits[j - 1]);
- int currentWordStart = extractRangeStartFromLong(wordLimits[j]);
- String textSpaces = text.substring(previousWordEnd, currentWordStart);
-
- if (!sourceSpaces.equals(textSpaces)) {
- ssb.setSpan(highlightSpan(nbHighlightSpans++),
- shift + previousWordEnd, shift + currentWordStart,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- previousCommonWordIndex = j;
- break;
- }
- }
- }
-
- // Finally, compare ends of Strings
- if (previousCommonWordIndex < words.length - 1) {
- int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 :
- extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
- int lastDifferentPosition = text.length();
- ssb.setSpan(highlightSpan(nbHighlightSpans++),
- shift + firstDifferentPosition, shift + lastDifferentPosition,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- } else {
- int lastSourceWordEnd = sourceWordLimits.length == 0 ? 0 :
- extractRangeEndFromLong(sourceWordLimits[sourceWordLimits.length - 1]);
- String sourceSpaces = sourceText.substring(lastSourceWordEnd, sourceText.length());
-
- int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 :
- extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
- String textSpaces = text.substring(lastCommonTextWordEnd, text.length());
-
- if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) {
- ssb.setSpan(highlightSpan(nbHighlightSpans++),
- shift + lastCommonTextWordEnd, shift + text.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
-
- // Final part, text after the current suggestion range.
- ssb.append(mText.subSequence(spanEnd, unionEnd).toString());
+ // Add the text before and after the span.
+ suggestionInfo.text.insert(0, mText.subSequence(unionStart, spanStart).toString());
+ suggestionInfo.text.append(mText.subSequence(spanEnd, unionEnd).toString());
}
@Override
@@ -9959,6 +9914,9 @@
suggestionSpansFlags[i]);
}
}
+
+ // Move cursor at the end of the replacement word
+ Selection.setSelection(editable, spanEnd + lengthDifference);
}
}
hide();
@@ -10074,14 +10032,22 @@
}
}
- ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
- mSelectionActionMode = startActionMode(actionModeCallback);
- final boolean selectionStarted = mSelectionActionMode != null;
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ boolean extractedTextModeWillBeStartedFullScreen = !(this instanceof ExtractEditText) &&
+ imm != null && imm.isFullscreenMode();
- if (selectionStarted && !mTextIsSelectable) {
+ // Do not start the action mode when extracted text will show up full screen, thus
+ // immediately hiding the newly created action bar, which would be visually distracting.
+ if (!extractedTextModeWillBeStartedFullScreen) {
+ ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
+ mSelectionActionMode = startActionMode(actionModeCallback);
+ }
+ final boolean selectionStarted = mSelectionActionMode != null ||
+ extractedTextModeWillBeStartedFullScreen;
+
+ if (selectionStarted && !mTextIsSelectable && imm != null) {
// Show the IME to be able to replace text, except when selecting non editable text.
- final InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) imm.showSoftInput(this, 0, null);
+ imm.showSoftInput(this, 0, null);
}
return selectionStarted;
@@ -11069,14 +11035,21 @@
* Hides the insertion controller and stops text selection mode, hiding the selection controller
*/
private void hideControllers() {
- hideInsertionPointCursorController();
- stopSelectionActionMode();
+ hideCursorControllers();
+ hideSpanControllers();
+ }
+ private void hideSpanControllers() {
if (mChangeWatcher != null) {
mChangeWatcher.hideControllers();
}
}
+ private void hideCursorControllers() {
+ hideInsertionPointCursorController();
+ stopSelectionActionMode();
+ }
+
/**
* Get the character offset closest to the specified absolute position. A typical use case is to
* pass the result of {@link MotionEvent#getX()} and {@link MotionEvent#getY()} to this method.
@@ -11362,6 +11335,15 @@
mResolvedDrawables = false;
}
+ /**
+ * @hide
+ */
+ protected void viewClicked(InputMethodManager imm) {
+ if (imm != null) {
+ imm.viewClicked(this);
+ }
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
@@ -11384,7 +11366,7 @@
private final TextPaint mTextPaint;
private boolean mUserSetTextScaleX;
private final Paint mHighlightPaint;
- private int mHighlightColor = 0x4C33B5E5;
+ private int mHighlightColor = 0x6633B5E5;
/**
* This is temporarily visible to fix bug 3085564 in webView. Do not rely on
* this field being protected. Will be restored as private when lineHeight
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 2350229..7865d50 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.Widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -30,8 +28,11 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.EditorInfo;
import android.widget.NumberPicker.OnValueChangeListener;
+import com.android.internal.R;
+
import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.Locale;
@@ -149,6 +150,8 @@
onTimeChanged();
}
});
+ EditText hourInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+ hourInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
// divider (only for the new widget style)
mDivider = (TextView) findViewById(R.id.divider);
@@ -184,6 +187,8 @@
onTimeChanged();
}
});
+ EditText minuteInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+ minuteInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
/* Get the localized am/pm strings and use them in the spinner */
mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
@@ -214,6 +219,8 @@
}
});
}
+ EditText amPmInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+ amPmInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
// update controls to initial state
updateHourControl();
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index cfecca5..ccca22e 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -346,7 +346,17 @@
}
public void setBackgroundDrawable(Drawable d) {
- mContainerView.setBackgroundDrawable(d);
+ mContainerView.setPrimaryBackground(d);
+ }
+
+ public void setStackedBackgroundDrawable(Drawable d) {
+ mContainerView.setStackedBackground(d);
+ }
+
+ public void setSplitBackgroundDrawable(Drawable d) {
+ if (mSplitView != null) {
+ mSplitView.setSplitBackground(d);
+ }
}
public View getCustomView() {
@@ -783,6 +793,7 @@
private Object mTag;
private Drawable mIcon;
private CharSequence mText;
+ private CharSequence mContentDesc;
private int mPosition = -1;
private View mCustomView;
@@ -878,6 +889,25 @@
public void select() {
selectTab(this);
}
+
+ @Override
+ public Tab setContentDescription(int resId) {
+ return setContentDescription(mContext.getResources().getText(resId));
+ }
+
+ @Override
+ public Tab setContentDescription(CharSequence contentDesc) {
+ mContentDesc = contentDesc;
+ if (mPosition >= 0) {
+ mTabScrollView.updateTab(mPosition);
+ }
+ return this;
+ }
+
+ @Override
+ public CharSequence getContentDescription() {
+ return mContentDesc;
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba2f5d4..3fba1be 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -58,9 +58,20 @@
private TextView mClearDefaultHint;
private PackageManager mPm;
+ private Intent makeMyIntent() {
+ Intent intent = new Intent(getIntent());
+ // The resolver activity is set to be hidden from recent tasks.
+ // we don't want this attribute to be propagated to the next activity
+ // being launched. Note that if the original Intent also had this
+ // flag set, we are now losing it. That should be a very rare case
+ // and we can live with this.
+ intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ return intent;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
- onCreate(savedInstanceState, new Intent(getIntent()),
+ onCreate(savedInstanceState, makeMyIntent(),
getResources().getText(com.android.internal.R.string.whichApplication),
null, null, true);
}
diff --git a/core/java/com/android/internal/backup/BackupConstants.java b/core/java/com/android/internal/backup/BackupConstants.java
index 3ee11bd..906b5d5 100644
--- a/core/java/com/android/internal/backup/BackupConstants.java
+++ b/core/java/com/android/internal/backup/BackupConstants.java
@@ -23,4 +23,5 @@
public static final int TRANSPORT_OK = 0;
public static final int TRANSPORT_ERROR = 1;
public static final int TRANSPORT_NOT_INITIALIZED = 2;
+ public static final int AGENT_ERROR = 3;
}
diff --git a/wifi/java/android/net/wifi/WpsConfiguration.aidl b/core/java/com/android/internal/policy/IFaceLockCallback.aidl
similarity index 63%
copy from wifi/java/android/net/wifi/WpsConfiguration.aidl
copy to core/java/com/android/internal/policy/IFaceLockCallback.aidl
index 6c26833..1eadc41 100644
--- a/wifi/java/android/net/wifi/WpsConfiguration.aidl
+++ b/core/java/com/android/internal/policy/IFaceLockCallback.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2010, The Android Open Source Project
+/*
+ * 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
+ * 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,
@@ -13,7 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.internal.policy;
-package android.net.wifi;
+import android.os.IBinder;
-parcelable WpsConfiguration;
+/** {@hide} */
+oneway interface IFaceLockCallback {
+ void unlock();
+ void cancel();
+ void sleepDevice();
+}
diff --git a/core/java/com/android/internal/policy/IFaceLockInterface.aidl b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
new file mode 100644
index 0000000..921b8c7
--- /dev/null
+++ b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.internal.policy;
+
+import android.os.IBinder;
+import com.android.internal.policy.IFaceLockCallback;
+
+/** {@hide} */
+interface IFaceLockInterface {
+ void startUi(IBinder containingWindowToken, int x, int y, int width, int height);
+ void stopUi();
+ void registerCallback(IFaceLockCallback cb);
+}
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index 146c7ac..e6538b0 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -34,6 +34,8 @@
* MenuPresenter for list-style menus.
*/
public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
+ private static final String TAG = "ListMenuPresenter";
+
Context mContext;
LayoutInflater mInflater;
MenuBuilder mMenu;
@@ -76,7 +78,7 @@
public void initForMenu(Context context, MenuBuilder menu) {
if (mThemeRes != 0) {
mContext = new ContextThemeWrapper(context, mThemeRes);
- } else if (mContext == null) {
+ } else if (mContext != null) {
mContext = context;
}
mInflater = LayoutInflater.from(mContext);
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index df2f717..6c11288 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.widget;
+import com.android.internal.R;
import com.android.internal.view.menu.ActionMenuPresenter;
import com.android.internal.view.menu.ActionMenuView;
@@ -23,6 +24,8 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -32,6 +35,7 @@
protected ActionMenuView mMenuView;
protected ActionMenuPresenter mActionMenuPresenter;
protected ActionBarContainer mSplitView;
+ protected int mContentHeight;
protected Animator mVisibilityAnim;
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
@@ -52,6 +56,30 @@
super(context, attrs, defStyle);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ // Action bar can change size on configuration changes.
+ // Reread the desired height from the theme-specified style.
+ TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar,
+ com.android.internal.R.attr.actionBarStyle, 0);
+ setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
+ a.recycle();
+ if (mActionMenuPresenter != null) {
+ mActionMenuPresenter.onConfigurationChanged(newConfig);
+ }
+ }
+
+ public void setContentHeight(int height) {
+ mContentHeight = height;
+ requestLayout();
+ }
+
+ public int getContentHeight() {
+ return mContentHeight;
+ }
+
public void setSplitView(ActionBarContainer splitView) {
mSplitView = splitView;
}
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index fd9ee08..f95de62 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -76,6 +76,21 @@
mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
}
+ public void setPrimaryBackground(Drawable bg) {
+ mBackground = bg;
+ invalidate();
+ }
+
+ public void setStackedBackground(Drawable bg) {
+ mStackedBackground = bg;
+ invalidate();
+ }
+
+ public void setSplitBackground(Drawable bg) {
+ mSplitBackground = bg;
+ invalidate();
+ }
+
/**
* Set the action bar into a "transitioning" state. While transitioning
* the bar will block focus and touch from all of its descendants. This
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 4fccc32..a631380 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -44,8 +44,6 @@
public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
private static final String TAG = "ActionBarContextView";
- private int mContentHeight;
-
private CharSequence mTitle;
private CharSequence mSubtitle;
@@ -94,15 +92,7 @@
a.recycle();
}
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mActionMenuPresenter != null) {
- mActionMenuPresenter.onConfigurationChanged(newConfig);
- }
- }
-
- public void setHeight(int height) {
+ public void setContentHeight(int height) {
mContentHeight = height;
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 63b0274..7434df3a 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -84,8 +84,6 @@
private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
- private int mContentHeight;
-
private int mNavigationMode;
private int mDisplayOptions = -1;
private CharSequence mTitle;
@@ -257,16 +255,6 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- // Action bar can change size on configuration changes.
- // Reread the desired height from the theme-specified style.
- TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar,
- com.android.internal.R.attr.actionBarStyle, 0);
- setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
- a.recycle();
- if (mActionMenuPresenter != null) {
- mActionMenuPresenter.onConfigurationChanged(newConfig);
- }
-
mTitleView = null;
mSubtitleView = null;
mTitleUpView = null;
@@ -277,6 +265,13 @@
if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
initTitle();
}
+
+ if (mTabScrollView != null && mIncludeTabs) {
+ ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
+ lp.width = LayoutParams.WRAP_CONTENT;
+ lp.height = LayoutParams.MATCH_PARENT;
+ mTabScrollView.setAllowCollapse(true);
+ }
}
@Override
@@ -304,15 +299,6 @@
addView(mIndeterminateProgressView);
}
- public void setContentHeight(int height) {
- mContentHeight = height;
- requestLayout();
- }
-
- public int getContentHeight() {
- return mContentHeight;
- }
-
public void setSplitActionBar(boolean splitActionBar) {
if (mSplitActionBar != splitActionBar) {
if (mMenuView != null) {
@@ -957,7 +943,7 @@
}
if (mContextView != null) {
- mContextView.setHeight(getMeasuredHeight());
+ mContextView.setContentHeight(getMeasuredHeight());
}
if (mProgressView != null && mProgressView.getVisibility() != GONE) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 804f28a..4d828c4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -106,8 +106,11 @@
private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
+ public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
+ public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
+ = "lockscreen.biometric_weak_fallback";
private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
@@ -373,6 +376,7 @@
setLockPatternEnabled(false);
saveLockPattern(null);
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
}
/**
@@ -400,6 +404,15 @@
* @param pattern The new pattern to save.
*/
public void saveLockPattern(List<LockPatternView.Cell> pattern) {
+ this.saveLockPattern(pattern, false);
+ }
+
+ /**
+ * Save a lock pattern.
+ * @param pattern The new pattern to save.
+ * @param isFallback Specifies if this is a fallback to biometric weak
+ */
+ public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
// Compute the hash
final byte[] hash = LockPatternUtils.patternToHash(pattern);
try {
@@ -417,7 +430,13 @@
if (pattern != null) {
keyStore.password(patternToString(pattern));
setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ if (!isFallback) {
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ } else {
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
+ setLong(PASSWORD_TYPE_ALTERNATE_KEY,
+ DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ }
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern
.size(), 0, 0, 0, 0, 0, 0);
} else {
@@ -493,6 +512,18 @@
* @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
*/
public void saveLockPassword(String password, int quality) {
+ this.saveLockPassword(password, quality, false);
+ }
+
+ /**
+ * Save a lock password. Does not ensure that the password is as good
+ * as the requested mode, but will adjust the mode to be as good as the
+ * pattern.
+ * @param password The password to save
+ * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+ * @param isFallback Specifies if this is a fallback to biometric weak
+ */
+ public void saveLockPassword(String password, int quality, boolean isFallback) {
// Compute the hash
final byte[] hash = passwordToHash(password);
try {
@@ -515,7 +546,12 @@
keyStore.password(password);
int computedQuality = computePasswordQuality(password);
- setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
+ if (!isFallback) {
+ setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
+ } else {
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
+ setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
+ }
if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int letters = 0;
int uppercase = 0;
@@ -590,7 +626,22 @@
* @return stored password quality
*/
public int getKeyguardStoredPasswordQuality() {
- return (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ int quality =
+ (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ // If the user has chosen to use weak biometric sensor, then return the backup locking
+ // method and treat biometric as a special case.
+ if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
+ quality =
+ (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
+ DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ }
+ return quality;
+ }
+
+ public boolean usingBiometricWeak() {
+ int quality =
+ (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
}
/**
@@ -726,6 +777,15 @@
}
/**
+ * @return Whether biometric weak lock is enabled.
+ */
+ public boolean isBiometricEnabled() {
+ // TODO: check if it's installed
+ return getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
+ == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+ }
+
+ /**
* Set whether the lock pattern is enabled.
*/
public void setLockPatternEnabled(boolean enabled) {
@@ -863,7 +923,8 @@
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
- || isPassword && savedPasswordExists();
+ || isPassword && savedPasswordExists()
+ || usingBiometricWeak() && isBiometricEnabled();
return secure;
}
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 71f9364..b7bc366 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -443,6 +443,10 @@
mTextView.setVisibility(GONE);
mTextView.setText(null);
}
+
+ if (mIconView != null) {
+ mIconView.setContentDescription(tab.getContentDescription());
+ }
}
}
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index b01dcd8..9313d0a 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -760,7 +760,8 @@
jint count = end - start;
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = gTextLayoutCache.getValue(paint, textArray, start, count, end, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
+ end, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
@@ -780,7 +781,8 @@
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = gTextLayoutCache.getValue(paint, textArray, start, count, contextCount, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
+ contextCount, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 7e89a37..fa9a7b7 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -257,7 +257,7 @@
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
// Return advances from the cache. Compute them if needed
- value = gTextLayoutCache.getValue(
+ value = TextLayoutCache::getInstance().getValue(
paint, chars, start, count, contextCount, dirFlags);
#else
value = new TextLayoutCacheValue();
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 9bb1b92..0a29d78 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -41,11 +41,6 @@
*/
#define USE_TEXT_LAYOUT_CACHE 1
-
-#if USE_TEXT_LAYOUT_CACHE
- static TextLayoutCache gTextLayoutCache;
-#endif
-
enum {
kBidi_LTR = 0,
kBidi_RTL = 1,
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index f04c5eb5..7f79277 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "TextLayoutCache"
+
#include "TextLayoutCache.h"
#include "TextLayout.h"
@@ -23,6 +25,12 @@
namespace android {
+//--------------------------------------------------------------------------------------------------
+#if USE_TEXT_LAYOUT_CACHE
+ ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache);
+#endif
+//--------------------------------------------------------------------------------------------------
+
TextLayoutCache::TextLayoutCache() :
mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
@@ -30,13 +38,6 @@
init();
}
-TextLayoutCache::TextLayoutCache(uint32_t max):
- mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity),
- mSize(0), mMaxSize(max),
- mCacheHitCount(0), mNanosecondsSaved(0) {
- init();
-}
-
TextLayoutCache::~TextLayoutCache() {
mCache.clear();
}
@@ -46,25 +47,21 @@
mDebugLevel = readRtlDebugLevel();
mDebugEnabled = mDebugLevel & kRtlDebugCaches;
- LOGD("Using TextLayoutCache debug level: %d - Debug Enabled: %d", mDebugLevel, mDebugEnabled);
+ LOGD("Using debug level: %d - Debug Enabled: %d", mDebugLevel, mDebugEnabled);
mCacheStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
- if (mDebugEnabled) {
- LOGD("TextLayoutCache start time: %lld", mCacheStartTime);
- }
- mInitialized = true;
if (mDebugEnabled) {
+ LOGD("Start time: %lld", mCacheStartTime);
#if RTL_USE_HARFBUZZ
- LOGD("TextLayoutCache is using HARFBUZZ");
+ LOGD("Using HARFBUZZ");
#else
- LOGD("TextLayoutCache is using ICU");
+ LOGD("Using ICU");
#endif
+ LOGD("Initialization is done");
}
- if (mDebugEnabled) {
- LOGD("TextLayoutCache initialization is done");
- }
+ mInitialized = true;
}
/*
@@ -147,8 +144,7 @@
// Cleanup to make some room if needed
if (mSize + size > mMaxSize) {
if (mDebugEnabled) {
- LOGD("TextLayoutCache: need to clean some entries "
- "for making some room for a new entry");
+ LOGD("Need to clean some entries for making some room for a new entry");
}
while (mSize + size > mMaxSize) {
// This will call the callback
@@ -213,7 +209,7 @@
float remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize));
float timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / 1000000000;
LOGD("------------------------------------------------");
- LOGD("TextLayoutCache stats");
+ LOGD("Cache stats");
LOGD("------------------------------------------------");
LOGD("pid : %d", getpid());
LOGD("running : %.0f seconds", timeRunningInSec);
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 10dee87..0d8d71f 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -25,6 +25,7 @@
#include <utils/GenerationCache.h>
#include <utils/Compare.h>
#include <utils/RefBase.h>
+#include <utils/Singleton.h>
#include <SkPaint.h>
#include <SkTemplates.h>
@@ -187,11 +188,11 @@
/**
* Cache of text layout information.
*/
-class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >
+class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >,
+ public Singleton<TextLayoutCache>
{
public:
TextLayoutCache();
- TextLayoutCache(uint32_t maxByteSize);
virtual ~TextLayoutCache();
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 2f5fd5a..1f4da3a 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -202,6 +202,13 @@
#define INPUT_OPERATION_GENERIC_FAILURE 5003
#define INPUT_OPERATION_SUCCESS 5004
+#define HEALTH_OPERATION_SUCCESS 6000
+#define HEALTH_OPERATION_ERROR 6001
+#define HEALTH_OPERATION_INVALID_ARGS 6002
+#define HEALTH_OPERATION_GENERIC_FAILURE 6003
+#define HEALTH_OPERATION_NOT_FOUND 6004
+#define HEALTH_OPERATION_NOT_ALLOWED 6005
+
#endif
} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index eee256a..0335ce7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -74,6 +74,7 @@
static jmethodID method_onPanDeviceConnectionResult;
static jmethodID method_onHealthDevicePropertyChanged;
static jmethodID method_onHealthDeviceChannelChanged;
+static jmethodID method_onHealthDeviceConnectionResult;
typedef event_loop_native_data_t native_data_t;
@@ -141,6 +142,9 @@
"(Ljava/lang/String;[Ljava/lang/String;)V");
method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
"(Ljava/lang/String;I)V");
+ method_onHealthDeviceConnectionResult = env->GetMethodID(clazz,
+ "onHealthDeviceConnectionResult",
+ "(II)V");
method_onHealthDevicePropertyChanged = env->GetMethodID(clazz, "onHealthDevicePropertyChanged",
"(Ljava/lang/String;[Ljava/lang/String;)V");
method_onHealthDeviceChannelChanged = env->GetMethodID(clazz, "onHealthDeviceChannelChanged",
@@ -1533,6 +1537,39 @@
free(user);
}
+void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
+ LOGV("%s", __FUNCTION__);
+
+ native_data_t *nat = (native_data_t *)n;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env;
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+
+ jint result = HEALTH_OPERATION_SUCCESS;
+ if (dbus_set_error_from_message(&err, msg)) {
+ if (!strcmp(err.name, BLUEZ_ERROR_IFC ".InvalidArgs")) {
+ result = HEALTH_OPERATION_INVALID_ARGS;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".HealthError")) {
+ result = HEALTH_OPERATION_ERROR;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotFound")) {
+ result = HEALTH_OPERATION_NOT_FOUND;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotAllowed")) {
+ result = HEALTH_OPERATION_NOT_ALLOWED;
+ } else {
+ result = HEALTH_OPERATION_GENERIC_FAILURE;
+ }
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+
+ LOGV("... Health Device Code = %d, result = %d", code, result);
+ jint code = *(int *) user;
+ env->CallVoidMethod(nat->me,
+ method_onHealthDeviceConnectionResult,
+ code,
+ result);
+ free(user);
+}
#endif
static JNINativeMethod sMethods[] = {
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 819449a..a49c918 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -78,8 +78,8 @@
void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
-void onConnectPanResult(DBusMessage *msg, void *user, void *n);
void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
+void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
@@ -1450,79 +1450,70 @@
}
static jboolean createChannelNative(JNIEnv *env, jobject object,
- jstring devicePath, jstring appPath, jstring config) {
+ jstring devicePath, jstring appPath, jstring config,
+ jint code) {
LOGV("%s", __FUNCTION__);
- jboolean result = JNI_FALSE;
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
- if (nat) {
- DBusError err;
- dbus_error_init(&err);
-
+ if (nat && eventLoopNat) {
const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
const char *c_app_path = env->GetStringUTFChars(appPath, NULL);
const char *c_config = env->GetStringUTFChars(config, NULL);
+ int *data = (int *) malloc(sizeof(int));
+ if (data == NULL) return JNI_FALSE;
- DBusMessage *reply = dbus_func_args(env, nat->conn,
- c_device_path,
- DBUS_HEALTH_DEVICE_IFACE,
- "CreateChannel",
- DBUS_TYPE_OBJECT_PATH, &c_app_path,
- DBUS_TYPE_STRING, &c_config,
- DBUS_TYPE_INVALID);
+ *data = code;
+ bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult,
+ data, eventLoopNat, c_device_path,
+ DBUS_HEALTH_DEVICE_IFACE, "CreateChannel",
+ DBUS_TYPE_OBJECT_PATH, &c_app_path,
+ DBUS_TYPE_STRING, &c_config,
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(devicePath, c_device_path);
env->ReleaseStringUTFChars(appPath, c_app_path);
env->ReleaseStringUTFChars(config, c_config);
- if (!reply) {
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- }
- } else {
- result = JNI_TRUE;
- }
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
- return result;
+ return JNI_FALSE;
}
static jboolean destroyChannelNative(JNIEnv *env, jobject object, jstring devicePath,
- jstring channelPath) {
+ jstring channelPath, jint code) {
LOGE("%s", __FUNCTION__);
- jboolean result = JNI_FALSE;
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
- if (nat) {
- DBusError err;
- dbus_error_init(&err);
-
+ if (nat && eventLoopNat) {
const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL);
+ int *data = (int *) malloc(sizeof(int));
+ if (data == NULL) return JNI_FALSE;
- DBusMessage *reply = dbus_func_args(env, nat->conn,
- c_device_path,
- DBUS_HEALTH_DEVICE_IFACE,
- "DestroyChannel",
- DBUS_TYPE_OBJECT_PATH, &c_channel_path,
- DBUS_TYPE_INVALID);
+ *data = code;
+ bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult,
+ data, eventLoopNat, c_device_path,
+ DBUS_HEALTH_DEVICE_IFACE, "DestroyChannel",
+ DBUS_TYPE_OBJECT_PATH, &c_channel_path,
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(devicePath, c_device_path);
env->ReleaseStringUTFChars(channelPath, c_channel_path);
- if (!reply) {
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- }
- } else {
- result = JNI_TRUE;
- }
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
- return result;
+ return JNI_FALSE;
}
static jstring getMainChannelNative(JNIEnv *env, jobject object, jstring devicePath) {
@@ -1659,6 +1650,7 @@
if (fileDesc == NULL) {
// FileDescriptor constructor has thrown an exception
releaseChannelFdNative(env, object, channelPath);
+ close(fd);
return NULL;
}
@@ -1667,7 +1659,7 @@
if (parcelFileDesc == NULL) {
// ParcelFileDescriptor constructor has thrown an exception
releaseChannelFdNative(env, object, channelPath);
- LOGE("---Parcel File Desc is null");
+ close(fd);
return NULL;
}
@@ -1754,9 +1746,10 @@
{"unregisterHealthApplicationNative", "(Ljava/lang/String;)Z",
(void *)unregisterHealthApplicationNative},
- {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+ {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
(void *)createChannelNative},
- {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)destroyChannelNative},
+ {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
+ (void *)destroyChannelNative},
{"getMainChannelNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getMainChannelNative},
{"getChannelApplicationNative", "(Ljava/lang/String;)Ljava/lang/String;",
(void *)getChannelApplicationNative},
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index bcf8e71..395e417 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -477,7 +477,7 @@
#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = gTextLayoutCache.getValue(paint, text, 0, count, count, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
@@ -507,7 +507,7 @@
#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = gTextLayoutCache.getValue(paint, text, start, count, contextCount, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f50cecd..72863a2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -75,6 +75,7 @@
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
<protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
<protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
@@ -86,6 +87,21 @@
<protected-broadcast android:name="android.bluetooth.device.action.NAME_FAILED" />
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
@@ -1483,19 +1499,23 @@
android:theme="@style/Theme.Holo.Dialog"
android:label="@string/heavy_weight_switcher_title"
android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true">
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen">
+ android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.DisableCarModeActivity"
android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true">
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.RingtonePickerActivity"
android:theme="@style/Theme.Holo.Dialog.Alert"
android:excludeFromRecents="true"
- android:multiprocess="true">
+ android:multiprocess="true"
+ android:process=":ui">
<intent-filter>
<action android:name="android.intent.action.RINGTONE_PICKER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -1506,18 +1526,21 @@
android:excludeFromRecents="true"
android:exported="true"
android:theme="@android:style/Theme.Holo.Dialog"
- android:label="@string/choose_account_label">
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.GrantCredentialsPermissionActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.Holo.DialogWhenLarge">
+ android:theme="@android:style/Theme.Holo.DialogWhenLarge"
+ android:process=":ui">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
android:theme="@android:style/Theme.Holo.Dialog"
- android:label="@string/sync_too_many_deletes">
+ android:label="@string/sync_too_many_deletes"
+ android:process=":ui">
</activity>
<activity android:name="com.android.server.ShutdownActivity"
@@ -1535,7 +1558,8 @@
<activity android:name="com.android.internal.app.NetInitiatedActivity"
android:theme="@style/Theme.Holo.Dialog.Alert"
- android:excludeFromRecents="true">
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<receiver android:name="com.android.server.BootReceiver" >
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index 2cc39438..b39d551 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -18,17 +18,17 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false">
- <scale android:fromXScale="1.0" android:toXScale="1.0"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+ <scale android:fromXScale="0.95" android:toXScale="1.0"
android:fromYScale="0.95" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
- android:fillEnabled="true" android:fillBefore="true"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="150"
- android:duration="250" />
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="150"
- android:duration="250"/>
-</set>
+ android:startOffset="200"
+ android:duration="300" />
+ <alpha android:fromAlpha="0" android:toAlpha="1.0"
+ android:interpolator="@interpolator/decelerate_cubic"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:startOffset="200"
+ android:duration="300"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index fded0be..ffbd38a 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -18,15 +18,18 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false">
- <scale android:fromXScale="1.0" android:toXScale="1.0"
- android:fromYScale="1.0" android:toYScale="0.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:fillEnabled="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="150" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="150"/>
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:duration="200" />
+ <scale android:fromXScale="1.0" android:toXScale="1.2"
+ android:fromYScale="1.0" android:toYScale="0.8"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@interpolator/accelerate_quint"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:duration="200" />
+ <!-- This is needed to keep the animation running while task_close_enter completes -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="500" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index c8ffaaf..d64f856 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -18,17 +18,17 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false">
- <scale android:fromXScale="1.0" android:toXScale="1.0"
- android:fromYScale=".9" android:toYScale="1.0"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+ <scale android:fromXScale="1.2" android:toXScale="1.0"
+ android:fromYScale=".8" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
- android:fillEnabled="true" android:fillBefore="true"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="150"
- android:duration="250" />
+ android:startOffset="300"
+ android:duration="240" />
<alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="150"
- android:duration="250"/>
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quad"
+ android:startOffset="300"
+ android:duration="300"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 06f3fc4..19f92c0 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -18,15 +18,18 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false">
- <scale android:fromXScale="1.0" android:toXScale="1.0"
- android:fromYScale="1.0" android:toYScale="0.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:fillEnabled="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="150" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillAfter="true"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_cubic"
- android:duration="150"/>
+ android:duration="200"/>
+ <scale android:fromXScale="1.0" android:toXScale="0.95"
+ android:fromYScale="1.0" android:toYScale="0.95"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:duration="300" />
+ <!-- This is needed to keep the animation running while task_open_enter completes -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="540" />
</set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-hdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..6c14157
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-hdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..f4ff16b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png
index 0d165bb..b0dc31f 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png
index 73c7e25..4bc2683 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png
index 1459eee..4af38fb 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png
index 04de530..d32f74c 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
index bab70fa..66adffe 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
index b46adfa..caeff9c 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
index db011be..6f747c8 100644
--- a/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
index d9a9a73..682b2fd 100644
--- a/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png
index 7264a7a..986ab0b 100644
--- a/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_holo_light.9.png b/core/res/res/drawable-hdpi/list_divider_holo_light.9.png
index 74f48f5..0279e17 100644
--- a/core/res/res/drawable-hdpi/list_divider_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo.9.png
index d06549c..4ea7afa 100644
--- a/core/res/res/drawable-hdpi/list_longpressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
index dae40ca..e20b02d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
index dae40ca..e20b02d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-mdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..ed4ba34
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-mdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..1983c68
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png
index 9e936b3..5461b9c 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png
index 0360104..5dc6f80 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png
index dd947d2..a70b53c 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png
index 51cfca2..c7a9896 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
index fd6e6c7..85d7aad 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
index 5db212c..f7b01e0 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
index 306cac8..6bf21e3 100644
--- a/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
index cc081ad..70fe31a 100644
--- a/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png
index aa8015d..986ab0b 100644
--- a/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_divider_holo_light.9.png b/core/res/res/drawable-mdpi/list_divider_holo_light.9.png
index c25c256..0279e17 100644
--- a/core/res/res/drawable-mdpi/list_divider_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo.9.png
index 2b8a0b3..3bf8e03 100644
--- a/core/res/res/drawable-mdpi/list_longpressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
index 4cbcee9..13cb131 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
index 4cbcee9..13cb131 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-nodpi/indicator_code_lock_drag_direction_green_up.png
deleted file mode 100644
index cc46f19..0000000
--- a/core/res/res/drawable-nodpi/indicator_code_lock_drag_direction_green_up.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-nodpi/indicator_code_lock_drag_direction_red_up.png
deleted file mode 100644
index cc46f19..0000000
--- a/core/res/res/drawable-nodpi/indicator_code_lock_drag_direction_red_up.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/list_divider_holo_dark.9.png b/core/res/res/drawable-nodpi/list_divider_holo_dark.9.png
deleted file mode 100644
index 2e7951f..0000000
--- a/core/res/res/drawable-nodpi/list_divider_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/list_divider_holo_light.9.png b/core/res/res/drawable-nodpi/list_divider_holo_light.9.png
deleted file mode 100644
index 17d8a54..0000000
--- a/core/res/res/drawable-nodpi/list_divider_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..55099d49
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..3c4701f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png
index 01efef4..7ef2db7 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png
index c287605..2283b4c 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png
index 9a496e8..6d2039e 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png
index e2a38b4..3c909b5 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
index 911722f..131d103 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
index da169bf..3e7dcdf 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png
index af72732..45a0f1d 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png
index 79c162f..528e554 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_divider_holo_dark.9.png
new file mode 100644
index 0000000..e62f011
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_holo_light.9.png b/core/res/res/drawable-xhdpi/list_divider_holo_light.9.png
new file mode 100644
index 0000000..65061c0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_horizontal_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_divider_horizontal_holo_dark.9.png
index a8ad54d..0c901de 100644
--- a/core/res/res/drawable-xhdpi/list_divider_horizontal_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_divider_horizontal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo.9.png
index e303022..eda10e6 100644
--- a/core/res/res/drawable-xhdpi/list_longpressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
index 4375032..ee5eb6f 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
index 4375032..ee5eb6f 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml
index 82e1f83..4057441 100644
--- a/core/res/res/layout/activity_chooser_view.xml
+++ b/core/res/res/layout/activity_chooser_view.xml
@@ -19,33 +19,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_chooser_view_content"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center"
- android:gravity="center"
- style="?android:attr/actionButtonStyle"
- android:padding="0dip">
-
- <FrameLayout
- android:id="@+id/default_activity_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:focusable="true"
- android:addStatesFromChildren="true"
- android:background="?android:attr/actionBarItemBackground">
-
- <ImageView android:id="@+id/image"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_gravity="center"
- android:layout_marginTop="4dip"
- android:layout_marginBottom="4dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip"
- android:scaleType="fitCenter"
- android:adjustViewBounds="true" />
-
- </FrameLayout>
+ style="?android:attr/activityChooserViewStyle">
<FrameLayout
android:id="@+id/expand_activities_button"
@@ -60,10 +36,32 @@
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_gravity="center"
- android:layout_marginTop="4dip"
- android:layout_marginBottom="4dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="2dip"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="12dip"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true" />
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/default_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:focusable="true"
+ android:addStatesFromChildren="true"
+ android:background="?android:attr/actionBarItemBackground">
+
+ <ImageView android:id="@+id/image"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_gravity="center"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="2dip"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="12dip"
android:scaleType="fitCenter"
android:adjustViewBounds="true" />
diff --git a/core/res/res/layout/activity_list_item.xml b/core/res/res/layout/activity_list_item.xml
index 7022fe1..572caf0 100644
--- a/core/res/res/layout/activity_list_item.xml
+++ b/core/res/res/layout/activity_list_item.xml
@@ -33,6 +33,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
- android:paddingLeft="6dip" />
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" />
</LinearLayout>
diff --git a/core/res/res/layout/activity_list_item_2.xml b/core/res/res/layout/activity_list_item_2.xml
index 3b84c733..a58ebfc 100644
--- a/core/res/res/layout/activity_list_item_2.xml
+++ b/core/res/res/layout/activity_list_item_2.xml
@@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:drawablePadding="14dip"
android:paddingLeft="16dip"
diff --git a/core/res/res/layout/alert_dialog_progress_holo.xml b/core/res/res/layout/alert_dialog_progress_holo.xml
new file mode 100644
index 0000000..94dbb2b
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_progress_holo.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content" android:layout_height="match_parent">
+ <ProgressBar android:id="@+id/progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:layout_centerHorizontal="true" />
+ <TextView
+ android:id="@+id/progress_percent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@id/progress"
+ />
+ <TextView
+ android:id="@+id/progress_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/progress"
+ />
+</RelativeLayout>
diff --git a/core/res/res/layout/progress_dialog_holo.xml b/core/res/res/layout/progress_dialog_holo.xml
new file mode 100644
index 0000000..9631efd
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_holo.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout android:id="@+id/body"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:baselineAligned="false"
+ android:padding="16dip">
+
+ <ProgressBar android:id="@android:id/progress"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:max="10000"
+ android:layout_marginRight="16dip" />
+
+ <TextView android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 66e3b8a..c0404be 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -23,8 +23,8 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:paddingLeft="10dip"
- android:paddingRight="15dip">
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip">
<!-- Activity icon when presenting dialog -->
<ImageView android:id="@+id/icon"
@@ -39,18 +39,18 @@
android:layout_height="wrap_content" >
<!-- Activity name -->
<TextView android:id="@android:id/text1"
- android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
- android:paddingLeft="10dip" />
+ android:paddingLeft="16dip" />
<!-- Extended activity info to distinguish between duplicate activity names -->
<TextView android:id="@android:id/text2"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
- android:paddingLeft="10dip" />
+ android:paddingLeft="16dip" />
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/simple_list_item_1.xml b/core/res/res/layout/simple_list_item_1.xml
index 252e006..c5e3efc 100644
--- a/core/res/res/layout/simple_list_item_1.xml
+++ b/core/res/res/layout/simple_list_item_1.xml
@@ -18,9 +18,9 @@
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
- android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>
diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml
index 9b6c62a..9369876 100644
--- a/core/res/res/layout/simple_list_item_2.xml
+++ b/core/res/res/layout/simple_list_item_2.xml
@@ -24,8 +24,8 @@
<TextView android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
- android:layout_marginTop="8dip"
+ android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:layout_marginTop="8dip"
android:textAppearance="?android:attr/textAppearanceListItem"
/>
@@ -33,7 +33,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/text1"
- android:layout_alignLeft="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
diff --git a/core/res/res/layout/simple_list_item_activated_1.xml b/core/res/res/layout/simple_list_item_activated_1.xml
index d60f93b..a5fb5d1 100644
--- a/core/res/res/layout/simple_list_item_activated_1.xml
+++ b/core/res/res/layout/simple_list_item_activated_1.xml
@@ -18,8 +18,10 @@
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:background="?android:attr/activatedBackgroundIndicator"
- android:minHeight="?android:attr/listPreferredItemHeight"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>
diff --git a/core/res/res/layout/simple_list_item_activated_2.xml b/core/res/res/layout/simple_list_item_activated_2.xml
index 5be5c92..8746f6f 100644
--- a/core/res/res/layout/simple_list_item_activated_2.xml
+++ b/core/res/res/layout/simple_list_item_activated_2.xml
@@ -27,9 +27,9 @@
<TextView android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
- android:layout_marginTop="8dip"
- android:textAppearance="?android:attr/textAppearanceLarge"
+ android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:layout_marginTop="6dip"
+ android:textAppearance="?android:attr/textAppearanceListItem"
/>
<TextView android:id="@android:id/text2"
diff --git a/core/res/res/layout/simple_list_item_checked.xml b/core/res/res/layout/simple_list_item_checked.xml
index 79d3a18..c9153f8 100644
--- a/core/res/res/layout/simple_list_item_checked.xml
+++ b/core/res/res/layout/simple_list_item_checked.xml
@@ -17,10 +17,10 @@
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceListItem"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:checkMark="?android:attr/textCheckMark"
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
/>
diff --git a/core/res/res/layout/simple_list_item_single_choice.xml b/core/res/res/layout/simple_list_item_single_choice.xml
index ac4a4a8..4a6cefa 100644
--- a/core/res/res/layout/simple_list_item_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_single_choice.xml
@@ -17,10 +17,10 @@
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceListItem"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
/>
diff --git a/core/res/res/layout/simple_spinner_item.xml b/core/res/res/layout/simple_spinner_item.xml
index 77929ee..61dc025 100644
--- a/core/res/res/layout/simple_spinner_item.xml
+++ b/core/res/res/layout/simple_spinner_item.xml
@@ -19,7 +19,7 @@
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
- style="?android:attr/spinnerItemStyle"
+ style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/values-bg-rBG/donottranslate-cldr.xml b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
deleted file mode 100644
index 4c38ad2..0000000
--- a/core/res/res/values-bg-rBG/donottranslate-cldr.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="month_long_standalone_january">януари</string>
- <string name="month_long_standalone_february">февруари</string>
- <string name="month_long_standalone_march">март</string>
- <string name="month_long_standalone_april">април</string>
- <string name="month_long_standalone_may">май</string>
- <string name="month_long_standalone_june">юни</string>
- <string name="month_long_standalone_july">юли</string>
- <string name="month_long_standalone_august">август</string>
- <string name="month_long_standalone_september">септември</string>
- <string name="month_long_standalone_october">октомври</string>
- <string name="month_long_standalone_november">ноември</string>
- <string name="month_long_standalone_december">декември</string>
-
- <string name="month_long_january">януари</string>
- <string name="month_long_february">февруари</string>
- <string name="month_long_march">март</string>
- <string name="month_long_april">април</string>
- <string name="month_long_may">май</string>
- <string name="month_long_june">юни</string>
- <string name="month_long_july">юли</string>
- <string name="month_long_august">август</string>
- <string name="month_long_september">септември</string>
- <string name="month_long_october">октомври</string>
- <string name="month_long_november">ноември</string>
- <string name="month_long_december">декември</string>
-
- <string name="month_medium_january">ян.</string>
- <string name="month_medium_february">февр.</string>
- <string name="month_medium_march">март</string>
- <string name="month_medium_april">апр.</string>
- <string name="month_medium_may">май</string>
- <string name="month_medium_june">юни</string>
- <string name="month_medium_july">юли</string>
- <string name="month_medium_august">авг.</string>
- <string name="month_medium_september">септ.</string>
- <string name="month_medium_october">окт.</string>
- <string name="month_medium_november">ноем.</string>
- <string name="month_medium_december">дек.</string>
-
- <string name="month_shortest_january">я</string>
- <string name="month_shortest_february">ф</string>
- <string name="month_shortest_march">м</string>
- <string name="month_shortest_april">а</string>
- <string name="month_shortest_may">м</string>
- <string name="month_shortest_june">ю</string>
- <string name="month_shortest_july">ю</string>
- <string name="month_shortest_august">а</string>
- <string name="month_shortest_september">с</string>
- <string name="month_shortest_october">о</string>
- <string name="month_shortest_november">н</string>
- <string name="month_shortest_december">д</string>
-
- <string name="day_of_week_long_sunday">неделя</string>
- <string name="day_of_week_long_monday">понеделник</string>
- <string name="day_of_week_long_tuesday">вторник</string>
- <string name="day_of_week_long_wednesday">сряда</string>
- <string name="day_of_week_long_thursday">четвъртък</string>
- <string name="day_of_week_long_friday">петък</string>
- <string name="day_of_week_long_saturday">събота</string>
-
- <string name="day_of_week_medium_sunday">нд</string>
- <string name="day_of_week_medium_monday">пн</string>
- <string name="day_of_week_medium_tuesday">вт</string>
- <string name="day_of_week_medium_wednesday">ср</string>
- <string name="day_of_week_medium_thursday">чт</string>
- <string name="day_of_week_medium_friday">пт</string>
- <string name="day_of_week_medium_saturday">сб</string>
-
- <string name="day_of_week_short_sunday">нд</string>
- <string name="day_of_week_short_monday">пн</string>
- <string name="day_of_week_short_tuesday">вт</string>
- <string name="day_of_week_short_wednesday">ср</string>
- <string name="day_of_week_short_thursday">чт</string>
- <string name="day_of_week_short_friday">пт</string>
- <string name="day_of_week_short_saturday">сб</string>
-
- <string name="day_of_week_shortest_sunday">н</string>
- <string name="day_of_week_shortest_monday">п</string>
- <string name="day_of_week_shortest_tuesday">в</string>
- <string name="day_of_week_shortest_wednesday">с</string>
- <string name="day_of_week_shortest_thursday">ч</string>
- <string name="day_of_week_shortest_friday">п</string>
- <string name="day_of_week_shortest_saturday">с</string>
-
- <string name="am">пр. об.</string>
- <string name="pm">сл. об.</string>
- <string name="yesterday">Вчера</string>
- <string name="today">Днес</string>
- <string name="tomorrow">Утре</string>
-
- <string name="hour_minute_24">%-k:%M</string>
- <string name="hour_minute_ampm">%-l:%M %p</string>
- <string name="hour_minute_cap_ampm">%-l:%M %p</string>
- <string name="twelve_hour_time_format">h:mm a</string>
- <string name="twenty_four_hour_time_format">H:mm</string>
- <string name="numeric_date">%d.%m.%Y</string>
- <string name="numeric_date_format">dd.MM.yyyy</string>
- <string name="numeric_date_template">"%s.%s.%s"</string>
- <string name="month_day_year">%d %B %Y</string>
- <string name="time_of_day">%H:%M:%S</string>
- <string name="date_and_time">%H:%M:%S %d.%m.%Y</string>
- <string name="date_time">%2$s %1$s</string>
- <string name="time_date">%1$s %3$s</string>
- <string name="abbrev_month_day_year">%d.%m.%Y</string>
- <string name="month_day">%-e %B</string>
- <string name="month">%-B</string>
- <string name="month_year">%B %Y</string>
- <string name="abbrev_month_day">%-e %b</string>
- <string name="abbrev_month">%b</string>
- <string name="abbrev_month_year">%b %Y</string>
- <string name="time1_time2">%1$s-%2$s</string>
- <string name="date1_date2">%2$s - %5$s</string>
- <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
- <string name="numeric_wday1_md1_wday2_md2">%3$s.%2$s, %1$s - %8$s.%7$s, %6$s</string>
- <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
- <string name="numeric_wday1_mdy1_wday2_mdy2">%3$s.%2$s.%4$s, %1$s - %8$s.%7$s.%9$s, %6$s</string>
- <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s.%2$s.%4$s, %1$s - %10$s %8$s.%7$s.%9$s, %6$s</string>
- <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
- <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %3$s.%2$s, %1$s - %10$s %8$s.%7$s, %6$s</string>
- <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
- <string name="wday1_date1_time1_wday2_date2_time2">%3$s %2$s, %1$s - %6$s %5$s, %4$s</string>
- <string name="wday1_date1_wday2_date2">%2$s, %1$s - %5$s, %4$s</string>
- <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
- <string name="time_wday_date">%1$s %3$s, %2$s</string>
- <string name="wday_date">%3$s, %2$s</string>
- <string name="time_wday">%1$s %2$s</string>
- <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
- <string name="same_year_wday1_md1_wday2_md2">%3$s %2$s, %1$s - %8$s %7$s, %6$s</string>
- <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
- <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %3$s %2$s, %1$s - %10$s %8$s %7$s, %6$s</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %3$s %2$s, %1$s - %10$s %8$s %7$s, %6$s</string>
- <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
- <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
- <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
- <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
- <string name="same_month_wday1_mdy1_wday2_mdy2">%3$s %2$s %4$s, %1$s - %8$s %7$s %9$s, %6$s</string>
- <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
- <string name="same_month_wday1_md1_wday2_md2">%3$s %2$s, %1$s - %8$s %7$s, %6$s</string>
- <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
- <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
- <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s, %1$s - %8$s %7$s y, %6$s</string>
- <string name="short_format_month">%b</string>
- <string name="full_wday_month_day_no_year">EEEE MMMM d</string>
- <string name="abbrev_wday_month_day_year">d MMM yyyy, E</string>
-</resources>
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
index 62f550a..dc8b3ad 100644
--- a/core/res/res/values-bg/donottranslate-cldr.xml
+++ b/core/res/res/values-bg/donottranslate-cldr.xml
@@ -128,22 +128,22 @@
<string name="wday_date">%3$s, %2$s</string>
<string name="time_wday">%1$s %2$s</string>
<string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
- <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%3$s %2$s, %1$s - %8$s %7$s, %6$s</string>
<string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
<string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %3$s %2$s, %1$s - %10$s %8$s %7$s, %6$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %3$s %2$s, %1$s - %10$s %8$s %7$s, %6$s</string>
<string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
<string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
<string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
<string name="same_month_wday1_mdy1_wday2_mdy2">%3$s %2$s %4$s, %1$s - %8$s %7$s %9$s, %6$s</string>
<string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
- <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%3$s %2$s, %1$s - %8$s %7$s, %6$s</string>
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s, %1$s - %8$s %7$s y, %6$s</string>
<string name="short_format_month">%b</string>
- <string name="full_wday_month_day_no_year">E, d MMMM</string>
- <string name="abbrev_wday_month_day_year">d MMM y, E</string>
+ <string name="full_wday_month_day_no_year">d MMMM, EEEE</string>
+ <string name="abbrev_wday_month_day_year">d MMM yyyy, E</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0bf5b0a..0fbb19a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -235,6 +235,11 @@
<!-- The list item height for search results. @hide -->
<attr name="searchResultListItemHeight" format="dimension" />
+ <!-- The preferred padding along the left edge of list items. -->
+ <attr name="listPreferredItemPaddingLeft" format="dimension" />
+ <!-- The preferred padding along the right edge of list items. -->
+ <attr name="listPreferredItemPaddingRight" format="dimension" />
+
<!-- The preferred TextAppearance for the primary text of list items. -->
<attr name="textAppearanceListItem" format="reference" />
<!-- The preferred TextAppearance for the primary text of small list items. -->
@@ -597,6 +602,9 @@
<!-- The DatePicker style. -->
<attr name="datePickerStyle" format="reference" />
+ <!-- Default ActivityChooserView style. -->
+ <attr name="activityChooserViewStyle" format="reference" />
+
<!-- Fast scroller styles -->
<eat-comment />
@@ -1543,6 +1551,8 @@
<attr name="multiChoiceItemLayout" format="reference" />
<attr name="singleChoiceItemLayout" format="reference" />
<attr name="listItemLayout" format="reference" />
+ <attr name="progressLayout" format="reference" />
+ <attr name="horizontalProgressLayout" format="reference" />
</declare-styleable>
<!-- Fragment animation class attributes. -->
@@ -1796,7 +1806,13 @@
<!-- Defines whether the vertical scrollbar track should always be drawn. -->
<attr name="scrollbarAlwaysDrawVerticalTrack" format="boolean" />
- <!-- Defines which edges should be fadeded on scrolling. -->
+ <!-- {@deprecated This attribute is deprecated and will be ignored as of
+ API level {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}.
+ Using fading edges may introduce noticeable performance
+ degradations and should be used only when required by the application's
+ visual design. To request fading edges with API level
+ {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and above,
+ use the <code>requiresFadingEdge</code> attribute instead.} -->
<attr name="fadingEdge">
<!-- No edge is faded. -->
<flag name="none" value="0x00000000" />
@@ -1805,6 +1821,15 @@
<!-- Fades vertical edges only. -->
<flag name="vertical" value="0x00002000" />
</attr>
+ <!-- Defines which edges should be faded on scrolling. -->
+ <attr name="requiresFadingEdge">
+ <!-- No edge is faded. -->
+ <flag name="none" value="0x00000000" />
+ <!-- Fades horizontal edges only. -->
+ <flag name="horizontal" value="0x00001000" />
+ <!-- Fades vertical edges only. -->
+ <flag name="vertical" value="0x00002000" />
+ </attr>
<!-- Defines the length of the fading edges. -->
<attr name="fadingEdgeLength" format="dimension" />
@@ -3924,10 +3949,6 @@
<!-- ========================== -->
<eat-comment />
- <declare-styleable name="AnimationSet">
- <attr name="shareInterpolator" format="boolean" />
- </declare-styleable>
-
<declare-styleable name="Animation">
<!-- Defines the interpolator used to smooth the animation movement in time. -->
<attr name="interpolator" />
@@ -3977,6 +3998,15 @@
<attr name="detachWallpaper" format="boolean" />
</declare-styleable>
+ <declare-styleable name="AnimationSet">
+ <attr name="shareInterpolator" format="boolean" />
+ <attr name="fillBefore" />
+ <attr name="fillAfter" />
+ <attr name="duration" />
+ <attr name="startOffset" />
+ <attr name="repeatMode" />
+ </declare-styleable>
+
<declare-styleable name="RotateAnimation">
<attr name="fromDegrees" />
<attr name="toDegrees" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2753eab..4f162f2 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -175,4 +175,7 @@
<!-- Width of the icon in a dropdown list -->
<dimen name="dropdownitem_icon_width">32dip</dimen>
+ <!-- Default width for a textview error popup -->
+ <dimen name="textview_error_popup_default_width">240dip</dimen>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bc2b907..ba8be2e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1745,20 +1745,6 @@
<public type="attr" name="accessibilityFlags" />
<public type="attr" name="canRetrieveWindowContent" />
- <public type="attr" name="targetDrawables" />
- <public type="attr" name="handleDrawable" />
- <public type="attr" name="leftChevronDrawable" />
- <public type="attr" name="rightChevronDrawable" />
- <public type="attr" name="topChevronDrawable" />
- <public type="attr" name="bottomChevronDrawable" />
- <public type="attr" name="waveDrawable" />
- <public type="attr" name="outerRadius" />
- <public type="attr" name="hitRadius" />
- <public type="attr" name="vibrationDuration" />
- <public type="attr" name="snapMargin" />
- <public type="attr" name="feedbackCount" />
- <public type="attr" name="verticalOffset" />
- <public type="attr" name="horizontalOffset" />
<public type="attr" name="listPreferredItemHeightLarge" />
<public type="attr" name="listPreferredItemHeightSmall" />
@@ -1798,6 +1784,16 @@
<public type="attr" name="textAppearanceListItem" />
<public type="attr" name="textAppearanceListItemSmall" />
+ <public type="attr" name="targetDescriptions" />
+ <public type="attr" name="directionDescriptions" />
+
+ <public type="attr" name="overridesImplicitlyEnabledSubtype" />
+
+ <public type="attr" name="listPreferredItemPaddingLeft" />
+ <public type="attr" name="listPreferredItemPaddingRight" />
+
+ <public type="attr" name="requiresFadingEdge" />
+
<public type="style" name="TextAppearance.SuggestionHighlight" />
<public type="style" name="Theme.Holo.Light.DarkActionBar" />
@@ -2007,8 +2003,4 @@
<public type="color" name="holo_purple" />
<public type="color" name="holo_blue_bright" />
- <public type="attr" name="targetDescriptions" />
- <public type="attr" name="directionDescriptions" />
-
- <public type="attr" name="overridesImplicitlyEnabledSubtype" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1a6a523..356a2ad 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -61,6 +61,8 @@
<item name="bottomBright">@android:drawable/popup_bottom_bright</item>
<item name="bottomMedium">@android:drawable/popup_bottom_medium</item>
<item name="centerMedium">@android:drawable/popup_center_medium</item>
+ <item name="progressLayout">@android:layout/progress_dialog</item>
+ <item name="horizontalProgressLayout">@android:layout/alert_dialog_progress</item>
</style>
<style name="Widget.PreferenceFrameLayout">
@@ -890,6 +892,14 @@
<item name="android:textSize">30sp</item>
</style>
+ <style name="Widget.ActivityChooserView">
+ <item name="android:gravity">center</item>
+ <item name="android:background">@android:drawable/ab_share_pack_holo_dark</item>
+ <item name="android:divider">?android:attr/dividerVertical</item>
+ <item name="android:showDividers">middle</item>
+ <item name="android:dividerPadding">6dip</item>
+ </style>
+
<style name="TextAppearance.SuggestionHighlight">
<item name="android:textSize">18sp</item>
<item name="android:textColor">@android:color/suggestion_highlight_text</item>
@@ -1651,6 +1661,9 @@
<item name="android:background">@null</item>
</style>
+ <style name="Widget.Holo.ActivityChooserView" parent="Widget.ActivityChooserView">
+ </style>
+
<style name="Widget.Holo.ImageWell" parent="Widget.ImageWell">
</style>
@@ -2071,6 +2084,10 @@
<style name="Widget.Holo.Light.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
</style>
+ <style name="Widget.Holo.Light.ActivityChooserView" parent="Widget.Holo.ActivityChooserView">
+ <item name="android:background">@android:drawable/ab_share_pack_holo_light</item>
+ </style>
+
<style name="Widget.Holo.Light.ImageWell" parent="Widget.ImageWell">
</style>
@@ -2335,6 +2352,8 @@
<item name="centerMedium">@android:drawable/dialog_middle_holo_dark</item>
<item name="layout">@android:layout/alert_dialog_holo</item>
<item name="listLayout">@android:layout/select_dialog_holo</item>
+ <item name="progressLayout">@android:layout/progress_dialog_holo</item>
+ <item name="horizontalProgressLayout">@android:layout/alert_dialog_progress_holo</item>
<item name="listItemLayout">@android:layout/select_dialog_item_holo</item>
<item name="multiChoiceItemLayout">@android:layout/select_dialog_multichoice_holo</item>
<item name="singleChoiceItemLayout">@android:layout/select_dialog_singlechoice_holo</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index f434ce8..d19c97f 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -124,6 +124,8 @@
<item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
<item name="textAppearanceListItem">?android:attr/textAppearanceLarge</item>
<item name="textAppearanceListItemSmall">?android:attr/textAppearanceLarge</item>
+ <item name="listPreferredItemPaddingLeft">6dip</item>
+ <item name="listPreferredItemPaddingRight">6dip</item>
<!-- @hide -->
<item name="searchResultListItemHeight">58dip</item>
@@ -269,7 +271,8 @@
<item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@android:style/Widget.ListPopupWindow</item>
<item name="popupMenuStyle">@android:style/Widget.PopupMenu</item>
-
+ <item name="activityChooserViewStyle">@android:style/Widget.ActivityChooserView</item>
+
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
<item name="preferenceCategoryStyle">@android:style/Preference.Category</item>
@@ -878,8 +881,8 @@
<item name="textColorSearchUrl">@android:color/search_url_text_holo</item>
<item name="textColorHighlight">@android:color/highlighted_text_holo_dark</item>
<item name="textColorHighlightInverse">@android:color/highlighted_text_holo_light</item>
- <item name="textColorLink">@android:color/link_text_holo_dark</item>
- <item name="textColorLinkInverse">@android:color/link_text_holo_light</item>
+ <item name="textColorLink">@android:color/holo_blue_light</item>
+ <item name="textColorLinkInverse">@android:color/holo_blue_light</item>
<item name="textColorAlertDialogListItem">@android:color/primary_text_holo_dark</item>
<item name="textAppearanceLarge">@android:style/TextAppearance.Holo.Large</item>
@@ -923,6 +926,8 @@
<item name="listPreferredItemHeightLarge">80dip</item>
<item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
<item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+ <item name="listPreferredItemPaddingLeft">8dip</item>
+ <item name="listPreferredItemPaddingRight">8dip</item>
<!-- @hide -->
<item name="searchResultListItemHeight">58dip</item>
@@ -1062,6 +1067,7 @@
<item name="listPopupWindowStyle">@android:style/Widget.Holo.ListPopupWindow</item>
<item name="popupMenuStyle">@android:style/Widget.Holo.PopupMenu</item>
<item name="stackViewStyle">@android:style/Widget.Holo.StackView</item>
+ <item name="activityChooserViewStyle">@android:style/Widget.Holo.ActivityChooserView</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.Holo.PreferenceScreen</item>
@@ -1182,8 +1188,8 @@
<item name="textColorSearchUrl">@android:color/search_url_text_holo</item>
<item name="textColorHighlight">@android:color/highlighted_text_holo_light</item>
<item name="textColorHighlightInverse">@android:color/highlighted_text_holo_dark</item>
- <item name="textColorLink">@android:color/link_text_holo_light</item>
- <item name="textColorLinkInverse">@android:color/link_text_holo_dark</item>
+ <item name="textColorLink">@android:color/holo_blue_light</item>
+ <item name="textColorLinkInverse">@android:color/holo_blue_light</item>
<item name="textColorAlertDialogListItem">@android:color/primary_text_holo_light</item>
<item name="textAppearanceLarge">@android:style/TextAppearance.Holo.Light.Large</item>
@@ -1227,6 +1233,8 @@
<item name="listPreferredItemHeightLarge">80dip</item>
<item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
<item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+ <item name="listPreferredItemPaddingLeft">8dip</item>
+ <item name="listPreferredItemPaddingRight">8dip</item>
<!-- @hide -->
<item name="searchResultListItemHeight">58dip</item>
@@ -1366,6 +1374,7 @@
<item name="listPopupWindowStyle">@android:style/Widget.Holo.Light.ListPopupWindow</item>
<item name="popupMenuStyle">@android:style/Widget.Holo.Light.PopupMenu</item>
<item name="stackViewStyle">@android:style/Widget.Holo.StackView</item>
+ <item name="activityChooserViewStyle">@android:style/Widget.Holo.Light.ActivityChooserView</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.Holo.PreferenceScreen</item>
@@ -1531,6 +1540,9 @@
<item name="textAppearance">@android:style/TextAppearance.Holo</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Inverse</item>
+
+ <item name="listPreferredItemPaddingLeft">16dip</item>
+ <item name="listPreferredItemPaddingRight">16dip</item>
</style>
<!-- Variation of Theme.Holo.Dialog that has a nice minumum width for
@@ -1620,6 +1632,9 @@
<item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
+
+ <item name="listPreferredItemPaddingLeft">16dip</item>
+ <item name="listPreferredItemPaddingRight">16dip</item>
</style>
<!-- Variation of Theme.Holo.Light.Dialog that has a nice minumum width for
diff --git a/data/etc/android.hardware.wifi.direct.xml b/data/etc/android.hardware.wifi.direct.xml
new file mode 100644
index 0000000..78cb474
--- /dev/null
+++ b/data/etc/android.hardware.wifi.direct.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<!-- This is the standard feature indicating that the device includes WiFi Direct. -->
+<permissions>
+ <feature name="android.hardware.wifi.direct" />
+</permissions>
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index ba9d76f..ff97670 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/videos/AndroidInSpace.240p.mp4 b/data/videos/AndroidInSpace.240p.mp4
new file mode 100644
index 0000000..e1445e4
--- /dev/null
+++ b/data/videos/AndroidInSpace.240p.mp4
Binary files differ
diff --git a/data/videos/Sunset.240p.mp4 b/data/videos/Sunset.240p.mp4
new file mode 100644
index 0000000..f5c533f
--- /dev/null
+++ b/data/videos/Sunset.240p.mp4
Binary files differ
diff --git a/data/videos/VideoPackage1.mk b/data/videos/VideoPackage1.mk
new file mode 100644
index 0000000..daff26f
--- /dev/null
+++ b/data/videos/VideoPackage1.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := frameworks/base/data/videos
+TARGET_PATH := system/media/video
+
+PRODUCT_COPY_FILES += \
+ $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
+ $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4
+
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 66ed104..a837294 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -37,6 +37,188 @@
public static final int MPERSP_1 = 7; //!< use with getValues/setValues
public static final int MPERSP_2 = 8; //!< use with getValues/setValues
+ /** @hide */
+ public static Matrix IDENTITY_MATRIX = new Matrix() {
+ void oops() {
+ throw new IllegalStateException("Matrix can not be modified");
+ }
+
+ @Override
+ public void set(Matrix src) {
+ oops();
+ }
+
+ @Override
+ public void reset() {
+ oops();
+ }
+
+ @Override
+ public void setTranslate(float dx, float dy) {
+ oops();
+ }
+
+ @Override
+ public void setScale(float sx, float sy, float px, float py) {
+ oops();
+ }
+
+ @Override
+ public void setScale(float sx, float sy) {
+ oops();
+ }
+
+ @Override
+ public void setRotate(float degrees, float px, float py) {
+ oops();
+ }
+
+ @Override
+ public void setRotate(float degrees) {
+ oops();
+ }
+
+ @Override
+ public void setSinCos(float sinValue, float cosValue, float px, float py) {
+ oops();
+ }
+
+ @Override
+ public void setSinCos(float sinValue, float cosValue) {
+ oops();
+ }
+
+ @Override
+ public void setSkew(float kx, float ky, float px, float py) {
+ oops();
+ }
+
+ @Override
+ public void setSkew(float kx, float ky) {
+ oops();
+ }
+
+ @Override
+ public boolean setConcat(Matrix a, Matrix b) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preTranslate(float dx, float dy) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preScale(float sx, float sy, float px, float py) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preScale(float sx, float sy) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preRotate(float degrees, float px, float py) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preRotate(float degrees) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preSkew(float kx, float ky, float px, float py) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preSkew(float kx, float ky) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean preConcat(Matrix other) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postTranslate(float dx, float dy) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postScale(float sx, float sy, float px, float py) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postScale(float sx, float sy) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postRotate(float degrees, float px, float py) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postRotate(float degrees) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postSkew(float kx, float ky, float px, float py) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postSkew(float kx, float ky) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean postConcat(Matrix other) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex,
+ int pointCount) {
+ oops();
+ return false;
+ }
+
+ @Override
+ public void setValues(float[] values) {
+ oops();
+ }
+ };
+
/**
* @hide
*/
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 72d233a3..0a3deb1 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -290,6 +290,8 @@
/**
* Implement this interface if you want to create an drawable that is RTL aware
+ *
+ * @hide
*/
public static interface Callback2 extends Callback {
/**
@@ -379,6 +381,8 @@
/**
* Use the current {@link android.graphics.drawable.Drawable.Callback2} implementation to get
* the resolved layout direction of this Drawable.
+ *
+ * @hide
*/
public int getResolvedLayoutDirectionSelf() {
final Callback callback = getCallback();
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 803bffb..a73403b 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -62,12 +62,17 @@
private:
// current locale (like "ja_JP"), created/destroyed with strdup()/free()
char *mLocale;
+ char *mSkipList;
+ int *mSkipIndex;
MediaScanResult doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client, bool noMedia);
MediaScanResult doProcessDirectoryEntry(
char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
struct dirent* entry, char* fileSpot);
+ void loadSkipList();
+ bool shouldSkipDirectory(char *path);
+
MediaScanner(const MediaScanner &);
MediaScanner &operator=(const MediaScanner &);
@@ -103,4 +108,3 @@
}; // namespace android
#endif // MEDIASCANNER_H
-
diff --git a/include/ui/Input.h b/include/ui/Input.h
index f1385a0..af899ef 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -660,15 +660,19 @@
static const uint32_t HISTORY_SIZE = 10;
// Oldest sample to consider when calculating the velocity.
- static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
+ static const nsecs_t MAX_AGE = 100 * 1000000; // 100 ms
// The minimum duration between samples when estimating velocity.
- static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
+ static const nsecs_t MIN_DURATION = 5 * 1000000; // 5 ms
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
Position positions[MAX_POINTERS];
+
+ inline const Position& getPosition(uint32_t id) const {
+ return positions[idBits.getIndexOfBit(id)];
+ }
};
uint32_t mIndex;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 392193b..5ccf87f 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -78,12 +78,8 @@
// conditionals don't get stripped... but that is probably what we want.
#if !LOG_NDEBUG
static const char *kReturnStrings[] = {
-#if 1 /* TODO: error update strings */
- "unknown",
-#else
+ "BR_ERROR",
"BR_OK",
- "BR_TIMEOUT",
- "BR_WAKEUP",
"BR_TRANSACTION",
"BR_REPLY",
"BR_ACQUIRE_RESULT",
@@ -94,25 +90,19 @@
"BR_RELEASE",
"BR_DECREFS",
"BR_ATTEMPT_ACQUIRE",
- "BR_EVENT_OCCURRED",
"BR_NOOP",
"BR_SPAWN_LOOPER",
"BR_FINISHED",
"BR_DEAD_BINDER",
- "BR_CLEAR_DEATH_NOTIFICATION_DONE"
-#endif
+ "BR_CLEAR_DEATH_NOTIFICATION_DONE",
+ "BR_FAILED_REPLY"
};
static const char *kCommandStrings[] = {
-#if 1 /* TODO: error update strings */
- "unknown",
-#else
- "BC_NOOP",
"BC_TRANSACTION",
"BC_REPLY",
"BC_ACQUIRE_RESULT",
"BC_FREE_BUFFER",
- "BC_TRANSACTION_COMPLETE",
"BC_INCREFS",
"BC_ACQUIRE",
"BC_RELEASE",
@@ -120,18 +110,12 @@
"BC_INCREFS_DONE",
"BC_ACQUIRE_DONE",
"BC_ATTEMPT_ACQUIRE",
- "BC_RETRIEVE_ROOT_OBJECT",
- "BC_SET_THREAD_ENTRY",
"BC_REGISTER_LOOPER",
"BC_ENTER_LOOPER",
"BC_EXIT_LOOPER",
- "BC_SYNC",
- "BC_STOP_PROCESS",
- "BC_STOP_SELF",
"BC_REQUEST_DEATH_NOTIFICATION",
"BC_CLEAR_DEATH_NOTIFICATION",
"BC_DEAD_BINDER_DONE"
-#endif
};
static const char* getReturnString(size_t idx)
@@ -154,30 +138,36 @@
{
const binder_transaction_data* btd =
(const binder_transaction_data*)data;
- out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
+ if (btd->target.handle < 1024) {
+ /* want to print descriptors in decimal; guess based on value */
+ out << "target.desc=" << btd->target.handle;
+ } else {
+ out << "target.ptr=" << btd->target.ptr;
+ }
+ out << " (cookie " << btd->cookie << ")" << endl
<< "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
<< "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
<< " bytes)" << endl
<< "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
- << " bytes)" << endl;
+ << " bytes)";
return btd+1;
}
static const void* printReturnCommand(TextOutput& out, const void* _cmd)
{
- static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
-
+ static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
int32_t code = *cmd++;
- if (code == BR_ERROR) {
+ size_t cmdIndex = code & 0xff;
+ if (code == (int32_t) BR_ERROR) {
out << "BR_ERROR: " << (void*)(*cmd++) << endl;
return cmd;
- } else if (code < 0 || code >= N) {
+ } else if (cmdIndex >= N) {
out << "Unknown reply: " << code << endl;
return cmd;
}
+ out << kReturnStrings[cmdIndex];
- out << kReturnStrings[code];
switch (code) {
case BR_TRANSACTION:
case BR_REPLY: {
@@ -213,6 +203,11 @@
const int32_t c = *cmd++;
out << ": death cookie " << (void*)c;
} break;
+
+ default:
+ // no details to show for: BR_OK, BR_DEAD_REPLY,
+ // BR_TRANSACTION_COMPLETE, BR_FINISHED
+ break;
}
out << endl;
@@ -221,16 +216,17 @@
static const void* printCommand(TextOutput& out, const void* _cmd)
{
- static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
-
+ static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
int32_t code = *cmd++;
- if (code < 0 || code >= N) {
+ size_t cmdIndex = code & 0xff;
+
+ if (cmdIndex >= N) {
out << "Unknown command: " << code << endl;
return cmd;
}
-
- out << kCommandStrings[code];
+ out << kCommandStrings[cmdIndex];
+
switch (code) {
case BC_TRANSACTION:
case BC_REPLY: {
@@ -254,7 +250,7 @@
case BC_RELEASE:
case BC_DECREFS: {
const int32_t d = *cmd++;
- out << ": descriptor=" << (void*)d;
+ out << ": desc=" << d;
} break;
case BC_INCREFS_DONE:
@@ -267,7 +263,7 @@
case BC_ATTEMPT_ACQUIRE: {
const int32_t p = *cmd++;
const int32_t d = *cmd++;
- out << ": decriptor=" << (void*)d << ", pri=" << p;
+ out << ": desc=" << d << ", pri=" << p;
} break;
case BC_REQUEST_DEATH_NOTIFICATION:
@@ -281,6 +277,11 @@
const int32_t c = *cmd++;
out << ": death cookie " << (void*)c;
} break;
+
+ default:
+ // no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
+ // BC_EXIT_LOOPER
+ break;
}
out << endl;
@@ -592,6 +593,7 @@
status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
{
+ LOG_REMOTEREFS("IPCThreadState::attemptIncStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
mOut.writeInt32(0); // xxx was thread priority
mOut.writeInt32(handle);
@@ -772,7 +774,7 @@
} else {
bwr.read_size = 0;
}
-
+
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != 0) {
@@ -789,7 +791,7 @@
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
-
+
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
@@ -809,7 +811,7 @@
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
-
+
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 7e8c7fd..349b9e3 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -91,6 +91,13 @@
#endif
}
+// TODO: This implementation is flawed and can generate T-junctions
+// in the mesh, which will in turn produce cracks when the
+// mesh is rotated/skewed. The easiest way to fix this would
+// be, for each row, to add new vertices shared with the previous
+// row when the two rows share an edge.
+// In practice, T-junctions do not appear often so this has yet
+// to be fixed.
void LayerRenderer::generateMesh() {
#if RENDER_LAYERS_AS_REGIONS
if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index a20a88e..32595e4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -63,36 +63,42 @@
// In this array, the index of each Blender equals the value of the first
// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
static const Blender gBlends[] = {
- { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }
+ { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
+ { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
+ { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+ { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
+ { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+ { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
+ { SkXfermode::kMultiply_Mode, GL_ZERO, GL_SRC_COLOR },
+ { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
};
// This array contains the swapped version of each SkXfermode. For instance
// this array's SrcOver blending mode is actually DstOver. You can refer to
// createLayer() for more information on the purpose of this array.
static const Blender gBlendsSwap[] = {
- { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }
+ { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
+ { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
+ { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+ { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
+ { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+ { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
+ { SkXfermode::kMultiply_Mode, GL_DST_COLOR, GL_ZERO },
+ { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
};
static const GLenum gTextureUnits[] = {
@@ -724,6 +730,8 @@
return;
}
+ // TODO: See LayerRenderer.cpp::generateMesh() for important
+ // information about this implementation
if (!layer->region.isEmpty()) {
size_t count;
const android::Rect* rects = layer->region.getArray(&count);
@@ -2487,7 +2495,7 @@
ProgramDescription& description, bool swapSrcDst) {
blend = blend || mode != SkXfermode::kSrcOver_Mode;
if (blend) {
- if (mode < SkXfermode::kPlus_Mode) {
+ if (mode <= SkXfermode::kScreen_Mode) {
if (!mCaches.blend) {
glEnable(GL_BLEND);
}
@@ -2540,15 +2548,7 @@
void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
if (paint) {
- if (!mCaches.extensions.hasFramebufferFetch()) {
- const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
- if (!isMode) {
- // Assume SRC_OVER
- *mode = SkXfermode::kSrcOver_Mode;
- }
- } else {
- *mode = getXfermode(paint->getXfermode());
- }
+ *mode = getXfermode(paint->getXfermode());
// Skia draws using the color's alpha channel if < 255
// Otherwise, it uses the paint's alpha
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 688b998..0d25823 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -752,6 +752,7 @@
switch (actionMasked) {
case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
// Clear all pointers on down before adding the new movement.
clear();
break;
@@ -764,12 +765,11 @@
clearPointers(downIdBits);
break;
}
- case AMOTION_EVENT_ACTION_OUTSIDE:
- case AMOTION_EVENT_ACTION_CANCEL:
- case AMOTION_EVENT_ACTION_SCROLL:
- case AMOTION_EVENT_ACTION_UP:
- case AMOTION_EVENT_ACTION_POINTER_UP:
- // Ignore these actions because they do not convey any new information about
+ case AMOTION_EVENT_ACTION_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ break;
+ default:
+ // Ignore all other actions because they do not convey any new information about
// pointer movement. We also want to preserve the last known velocity of the pointers.
// Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
// of the pointers that went up. ACTION_POINTER_UP does include the new position of
@@ -814,68 +814,36 @@
bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
const Movement& newestMovement = mMovements[mIndex];
if (newestMovement.idBits.hasBit(id)) {
- // Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
- nsecs_t minTime = newestMovement.eventTime - MAX_AGE;
- uint32_t oldestIndex = mIndex;
- uint32_t numTouches = 1;
- do {
- uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
- const Movement& nextOldestMovement = mMovements[nextOldestIndex];
- if (!nextOldestMovement.idBits.hasBit(id)
- || nextOldestMovement.eventTime < minTime) {
- break;
- }
- oldestIndex = nextOldestIndex;
- } while (++numTouches < HISTORY_SIZE);
-
- // Calculate an exponentially weighted moving average of the velocity estimate
- // at different points in time measured relative to the oldest sample.
- // This is essentially an IIR filter. Newer samples are weighted more heavily
- // than older samples. Samples at equal time points are weighted more or less
- // equally.
- //
- // One tricky problem is that the sample data may be poorly conditioned.
- // Sometimes samples arrive very close together in time which can cause us to
- // overestimate the velocity at that time point. Most samples might be measured
- // 16ms apart but some consecutive samples could be only 0.5sm apart because
- // the hardware or driver reports them irregularly or in bursts.
+ const Position& newestPosition = newestMovement.getPosition(id);
float accumVx = 0;
float accumVy = 0;
- uint32_t index = oldestIndex;
- uint32_t samplesUsed = 0;
- const Movement& oldestMovement = mMovements[oldestIndex];
- const Position& oldestPosition =
- oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
- nsecs_t lastDuration = 0;
+ float duration = 0;
- while (numTouches-- > 1) {
- if (++index == HISTORY_SIZE) {
- index = 0;
- }
+ // Iterate over movement samples in reverse time order and accumulate velocity.
+ uint32_t index = mIndex;
+ do {
+ index = (index == 0 ? HISTORY_SIZE : index) - 1;
const Movement& movement = mMovements[index];
- nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
-
- // If the duration between samples is small, we may significantly overestimate
- // the velocity. Consequently, we impose a minimum duration constraint on the
- // samples that we include in the calculation.
- if (duration >= MIN_DURATION) {
- const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)];
- float scale = 1000000000.0f / duration; // one over time delta in seconds
- float vx = (position.x - oldestPosition.x) * scale;
- float vy = (position.y - oldestPosition.y) * scale;
-
- accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
- accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
-
- lastDuration = duration;
- samplesUsed += 1;
+ if (!movement.idBits.hasBit(id)) {
+ break;
}
- }
+
+ nsecs_t age = newestMovement.eventTime - movement.eventTime;
+ if (age > MAX_AGE) {
+ break;
+ }
+
+ const Position& position = movement.getPosition(id);
+ accumVx += newestPosition.x - position.x;
+ accumVy += newestPosition.y - position.y;
+ duration += age;
+ } while (index != mIndex);
// Make sure we used at least one sample.
- if (samplesUsed != 0) {
- *outVx = accumVx;
- *outVy = accumVy;
+ if (duration >= MIN_DURATION) {
+ float scale = 1000000000.0f / duration; // one over time delta in seconds
+ *outVx = accumVx * scale;
+ *outVy = accumVy * scale;
return true;
}
}
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
index 4dfa578..ceca435 100644
--- a/libs/utils/Static.cpp
+++ b/libs/utils/Static.cpp
@@ -56,7 +56,9 @@
protected:
virtual status_t writeLines(const struct iovec& vec, size_t N)
{
- android_writevLog(&vec, N);
+ //android_writevLog(&vec, N); <-- this is now a no-op
+ if (N != 1) LOGI("WARNING: writeLines N=%d\n", N);
+ LOGI("%.*s", vec.iov_len, (const char*) vec.iov_base);
return NO_ERROR;
}
};
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 25c4200..cd8bb1d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1717,12 +1717,11 @@
/**
- * @hide
- * CANDIDATE FOR SDK
* Registers the remote control client for providing information to display on the remote
* controls.
- * @param rcClient the remote control client associated responsible
- * for providing the information to display on the remote control.
+ * @param rcClient The remote control client from which remote controls will receive
+ * information to display.
+ * @see RemoteControlClient
*/
public void registerRemoteControlClient(RemoteControlClient rcClient) {
if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
@@ -1741,11 +1740,9 @@
}
/**
- * @hide
- * CANDIDATE FOR SDK
* Unregisters the remote control client that was providing information to display on the
- * remotes.
- * @param rcClient the remote control client to unregister
+ * remote controls.
+ * @param rcClient The remote control client to unregister.
* @see #registerRemoteControlClient(RemoteControlClient)
*/
public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index d233f92..f5e1416 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -343,9 +343,8 @@
readPersistedSettings();
mSettingsObserver = new SettingsObserver();
createStreamStates();
- // Call setMode() to initialize mSetModeDeathHandlers
- mMode = AudioSystem.MODE_INVALID;
- setMode(AudioSystem.MODE_NORMAL, null);
+
+ mMode = AudioSystem.MODE_NORMAL;
mMediaServerOk = true;
// Call setRingerModeInt() to apply correct mute
@@ -768,37 +767,27 @@
private int mPid;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
- SetModeDeathHandler(IBinder cb) {
+ SetModeDeathHandler(IBinder cb, int pid) {
mCb = cb;
- mPid = Binder.getCallingPid();
+ mPid = pid;
}
public void binderDied() {
+ IBinder newModeOwner = null;
synchronized(mSetModeDeathHandlers) {
Log.w(TAG, "setMode() client died");
int index = mSetModeDeathHandlers.indexOf(this);
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
} else {
- mSetModeDeathHandlers.remove(this);
- // If dead client was a the top of client list,
- // apply next mode in the stack
- if (index == 0) {
- // mSetModeDeathHandlers is never empty as the initial entry
- // created when AudioService starts is never removed
- SetModeDeathHandler hdlr = mSetModeDeathHandlers.get(0);
- int mode = hdlr.getMode();
- if (AudioService.this.mMode != mode) {
- if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
- AudioService.this.mMode = mode;
- if (mode != AudioSystem.MODE_NORMAL) {
- disconnectBluetoothSco(mCb);
- }
- }
- }
- }
+ newModeOwner = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
}
}
+ // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+ // SCO connections not started by the application changing the mode
+ if (newModeOwner != null) {
+ disconnectBluetoothSco(newModeOwner);
+ }
}
public int getPid() {
@@ -828,60 +817,97 @@
return;
}
- synchronized (mSettingsLock) {
+ IBinder newModeOwner = null;
+ synchronized(mSetModeDeathHandlers) {
if (mode == AudioSystem.MODE_CURRENT) {
mode = mMode;
}
- if (mode != mMode) {
+ newModeOwner = setModeInt(mode, cb, Binder.getCallingPid());
+ }
+ // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+ // SCO connections not started by the application changing the mode
+ if (newModeOwner != null) {
+ disconnectBluetoothSco(newModeOwner);
+ }
+ }
- // automatically handle audio focus for mode changes
- handleFocusForCalls(mMode, mode, cb);
+ // must be called synchronized on mSetModeDeathHandlers
+ // setModeInt() returns a non null IBInder if the audio mode was successfully set to
+ // any mode other than NORMAL.
+ IBinder setModeInt(int mode, IBinder cb, int pid) {
+ IBinder newModeOwner = null;
+ if (cb == null) {
+ Log.e(TAG, "setModeInt() called with null binder");
+ return newModeOwner;
+ }
- if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
- mMode = mode;
-
- synchronized(mSetModeDeathHandlers) {
- SetModeDeathHandler hdlr = null;
- Iterator iter = mSetModeDeathHandlers.iterator();
- while (iter.hasNext()) {
- SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
- if (h.getBinder() == cb) {
- hdlr = h;
- // Remove from client list so that it is re-inserted at top of list
- iter.remove();
- break;
- }
- }
- if (hdlr == null) {
- hdlr = new SetModeDeathHandler(cb);
- // cb is null when setMode() is called by AudioService constructor
- if (cb != null) {
- // Register for client death notification
- try {
- cb.linkToDeath(hdlr, 0);
- } catch (RemoteException e) {
- // Client has died!
- Log.w(TAG, "setMode() could not link to "+cb+" binder death");
- }
- }
- }
- // Last client to call setMode() is always at top of client list
- // as required by SetModeDeathHandler.binderDied()
- mSetModeDeathHandlers.add(0, hdlr);
- hdlr.setMode(mode);
- }
-
- // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
- // SCO connections not started by the application changing the mode
- if (mode != AudioSystem.MODE_NORMAL) {
- disconnectBluetoothSco(cb);
- }
+ SetModeDeathHandler hdlr = null;
+ Iterator iter = mSetModeDeathHandlers.iterator();
+ while (iter.hasNext()) {
+ SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
+ if (h.getPid() == pid) {
+ hdlr = h;
+ // Remove from client list so that it is re-inserted at top of list
+ iter.remove();
+ hdlr.getBinder().unlinkToDeath(hdlr, 0);
+ break;
+ }
+ }
+ int status = AudioSystem.AUDIO_STATUS_OK;
+ do {
+ if (mode == AudioSystem.MODE_NORMAL) {
+ // get new mode from client at top the list if any
+ if (!mSetModeDeathHandlers.isEmpty()) {
+ hdlr = mSetModeDeathHandlers.get(0);
+ cb = hdlr.getBinder();
+ mode = hdlr.getMode();
}
+ } else {
+ if (hdlr == null) {
+ hdlr = new SetModeDeathHandler(cb, pid);
+ }
+ // Register for client death notification
+ try {
+ cb.linkToDeath(hdlr, 0);
+ } catch (RemoteException e) {
+ // Client has died!
+ Log.w(TAG, "setMode() could not link to "+cb+" binder death");
+ }
+
+ // Last client to call setMode() is always at top of client list
+ // as required by SetModeDeathHandler.binderDied()
+ mSetModeDeathHandlers.add(0, hdlr);
+ hdlr.setMode(mode);
+ }
+
+ if (mode != mMode) {
+ status = AudioSystem.setPhoneState(mode);
+ if (status == AudioSystem.AUDIO_STATUS_OK) {
+ // automatically handle audio focus for mode changes
+ handleFocusForCalls(mMode, mode, cb);
+ mMode = mode;
+ } else {
+ if (hdlr != null) {
+ mSetModeDeathHandlers.remove(hdlr);
+ cb.unlinkToDeath(hdlr, 0);
+ }
+ // force reading new top of mSetModeDeathHandlers stack
+ mode = AudioSystem.MODE_NORMAL;
+ }
+ } else {
+ status = AudioSystem.AUDIO_STATUS_OK;
+ }
+ } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
+
+ if (status == AudioSystem.AUDIO_STATUS_OK) {
+ if (mode != AudioSystem.MODE_NORMAL) {
+ newModeOwner = cb;
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false);
}
+ return newModeOwner;
}
/** pre-condition: oldMode != newMode */
@@ -1345,36 +1371,36 @@
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
// Accept SCO audio activation only in NORMAL audio mode or if the mode is
// currently controlled by the same client process.
- if ((AudioService.this.mMode == AudioSystem.MODE_NORMAL ||
- mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
- mBluetoothHeadsetDevice != null &&
- (mScoAudioState == SCO_STATE_INACTIVE ||
- mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
- if (mScoAudioState == SCO_STATE_INACTIVE) {
- if (mBluetoothHeadset != null) {
- if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice)) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- } else {
- broadcastScoConnectionState(
- AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ synchronized(mSetModeDeathHandlers) {
+ if ((mSetModeDeathHandlers.isEmpty() ||
+ mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
+ (mScoAudioState == SCO_STATE_INACTIVE ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+ if (mScoAudioState == SCO_STATE_INACTIVE) {
+ if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
+ if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice)) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ } else {
+ broadcastScoConnectionState(
+ AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
+ } else if (getBluetoothHeadset()) {
+ mScoAudioState = SCO_STATE_ACTIVATE_REQ;
}
- } else if (getBluetoothHeadset()) {
- mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+ } else {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
}
} else {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
- } else {
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
- mBluetoothHeadsetDevice != null &&
(mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
- if (mBluetoothHeadset != null) {
+ if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
mBluetoothHeadsetDevice)) {
mScoAudioState = SCO_STATE_INACTIVE;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index d7b85e4..daa25e0 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -17,7 +17,6 @@
package android.media;
import android.content.ComponentName;
-import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -31,15 +30,14 @@
import android.util.Log;
import java.lang.IllegalArgumentException;
-import java.util.HashMap;
/**
- * @hide
- * CANDIDATE FOR SDK
* RemoteControlClient enables exposing information meant to be consumed by remote controls
- * capable of displaying metadata, album art and media transport control buttons.
- * A remote control client object is associated with a media button event receiver
- * when registered through
+ * capable of displaying metadata, artwork and media transport control buttons.
+ * A remote control client object is associated with a media button event receiver. This
+ * event receiver must have been previously registered with
+ * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the
+ * RemoteControlClient can be registered through
* {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
*/
public class RemoteControlClient
@@ -110,7 +108,8 @@
public final static int PLAYSTATE_ERROR = 9;
/**
* @hide
- * The value of a playback state when none has been declared
+ * The value of a playback state when none has been declared.
+ * Intentionally hidden as an application shouldn't set such a playback state value.
*/
public final static int PLAYSTATE_NONE = 0;
@@ -122,7 +121,7 @@
*/
public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
/**
- * Flag indicating a RemoteControlClient makes use of the "rewing" media key.
+ * Flag indicating a RemoteControlClient makes use of the "rewind" media key.
*
* @see #setTransportControlFlags(int)
* @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
@@ -173,7 +172,9 @@
/**
* @hide
- * The flags for when no media keys are declared supported
+ * The flags for when no media keys are declared supported.
+ * Intentionally hidden as an application shouldn't set the transport control flags
+ * to this value.
*/
public final static int FLAGS_KEY_MEDIA_NONE = 0;
@@ -184,29 +185,29 @@
public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
/**
* @hide
- * FIXME doc not valid
* Flag used to signal that the transport control buttons supported by the
- * RemoteControlClient have changed.
+ * RemoteControlClient are requested.
* This can for instance happen when playback is at the end of a playlist, and the "next"
* operation is not supported anymore.
*/
public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
/**
* @hide
- * FIXME doc not valid
- * Flag used to signal that the playback state of the RemoteControlClient has changed.
+ * Flag used to signal that the playback state of the RemoteControlClient is requested.
*/
public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
/**
* @hide
- * FIXME doc not valid
- * Flag used to signal that the album art for the RemoteControlClient has changed.
+ * Flag used to signal that the album art for the RemoteControlClient is requested.
*/
public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
/**
* Class constructor.
- * @param mediaButtonEventReceiver the receiver for the media button events.
+ * @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
+ * been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
+ * before this new RemoteControlClient can itself be registered with
+ * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
* @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
* @see AudioManager#registerRemoteControlClient(RemoteControlClient)
*/
@@ -227,8 +228,11 @@
/**
* Class constructor for a remote control client whose internal event handling
* happens on a user-provided Looper.
- * @param mediaButtonEventReceiver the receiver for the media button events.
- * @param looper the Looper running the event loop.
+ * @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
+ * been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
+ * before this new RemoteControlClient can itself be registered with
+ * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
+ * @param looper The Looper running the event loop.
* @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
* @see AudioManager#registerRemoteControlClient(RemoteControlClient)
*/
@@ -257,11 +261,28 @@
/**
* Class used to modify metadata in a {@link RemoteControlClient} object.
+ * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
+ * on which you set the metadata for the RemoteControlClient instance. Once all the information
+ * has been set, use {@link #apply()} to make it the new metadata that should be displayed
+ * for the associated client. Once the metadata has been "applied", you cannot reuse this
+ * instance of the MetadataEditor.
*/
public class MetadataEditor {
+ /**
+ * @hide
+ */
protected boolean mMetadataChanged;
+ /**
+ * @hide
+ */
protected boolean mArtworkChanged;
+ /**
+ * @hide
+ */
protected Bitmap mEditorArtwork;
+ /**
+ * @hide
+ */
protected Bundle mEditorMetadata;
private boolean mApplied = false;
@@ -277,13 +298,18 @@
/**
* The metadata key for the content artwork / album art.
*/
- public final static int METADATA_KEY_ARTWORK = 100;
+ public final static int BITMAP_KEY_ARTWORK = 100;
+ /**
+ * @hide
+ * TODO(jmtrivi) have lockscreen and music move to the new key name
+ */
+ public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
/**
* Adds textual information to be displayed.
* Note that none of the information added after {@link #apply()} has been called,
* will be displayed.
- * @param key the identifier of a the metadata field to set. Valid values are
+ * @param key The identifier of a the metadata field to set. Valid values are
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
@@ -294,11 +320,11 @@
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
- * .
- * @param value the text for the given key, or {@code null} to signify there is no valid
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+ * @param value The text for the given key, or {@code null} to signify there is no valid
* information for the field.
- * @return FIXME description
+ * @return Returns a reference to the same MetadataEditor object, so you can chain put
+ * calls together.
*/
public synchronized MetadataEditor putString(int key, String value)
throws IllegalArgumentException {
@@ -315,15 +341,18 @@
}
/**
- * FIXME javadoc
+ * Adds numerical information to be displayed.
+ * Note that none of the information added after {@link #apply()} has been called,
+ * will be displayed.
* @param key the identifier of a the metadata field to set. Valid values are
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
* expressed in milliseconds),
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
- * @param value FIXME javadoc
- * @return FIXME javadoc
+ * @param value The long value for the given key
+ * @return Returns a reference to the same MetadataEditor object, so you can chain put
+ * calls together.
* @throws IllegalArgumentException
*/
public synchronized MetadataEditor putLong(int key, long value)
@@ -342,9 +371,11 @@
/**
* Sets the album / artwork picture to be displayed on the remote control.
- * @param key FIXME description
- * @param bitmap the bitmap for the artwork, or null if there isn't any.
- * @return FIXME description
+ * @param key the identifier of the bitmap to set. The only valid value is
+ * {@link #BITMAP_KEY_ARTWORK}
+ * @param bitmap The bitmap for the artwork, or null if there isn't any.
+ * @return Returns a reference to the same MetadataEditor object, so you can chain put
+ * calls together.
* @throws IllegalArgumentException
* @see android.graphics.Bitmap
*/
@@ -354,7 +385,7 @@
Log.e(TAG, "Can't edit a previously applied MetadataEditor");
return this;
}
- if (key != METADATA_KEY_ARTWORK) {
+ if (key != BITMAP_KEY_ARTWORK) {
throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
}
if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
@@ -369,7 +400,8 @@
}
/**
- * FIXME description
+ * Clears all the metadata that has been set since the MetadataEditor instance was
+ * created with {@link RemoteControlClient#editMetadata(boolean)}.
*/
public synchronized void clear() {
if (mApplied) {
@@ -381,7 +413,10 @@
}
/**
- * FIXME description
+ * Associates all the metadata that has been set since the MetadataEditor instance was
+ * created with {@link RemoteControlClient#editMetadata(boolean)}, or since
+ * {@link #clear()} was called, with the RemoteControlClient. Once "applied",
+ * this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
*/
public synchronized void apply() {
if (mApplied) {
@@ -408,9 +443,10 @@
}
/**
- * FIXME description
- * @param startEmpty
- * @return
+ * Creates a {@link MetadataEditor}.
+ * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
+ * was previously applied to the RemoteControlClient, or true if it is to be created empty.
+ * @return a new MetadataEditor instance.
*/
public MetadataEditor editMetadata(boolean startEmpty) {
MetadataEditor editor = new MetadataEditor();
@@ -430,7 +466,7 @@
/**
* Sets the current playback state.
- * @param state the current playback state, one of the following values:
+ * @param state The current playback state, one of the following values:
* {@link #PLAYSTATE_STOPPED},
* {@link #PLAYSTATE_PAUSED},
* {@link #PLAYSTATE_PLAYING},
@@ -453,7 +489,7 @@
/**
* Sets the flags for the media transport control buttons that this client supports.
- * @param a combination of the following flags:
+ * @param transportControlFlags A combination of the following flags:
* {@link #FLAG_KEY_MEDIA_PREVIOUS},
* {@link #FLAG_KEY_MEDIA_REWIND},
* {@link #FLAG_KEY_MEDIA_PLAY},
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index aa0a2e9..d7b8eaa 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -3758,65 +3758,33 @@
/**
* This method extracts a frame from the input file
- * and returns the frame as a bitmap
- *
- * @param inputFile The inputFile
- * @param width The width of the output frame
- * @param height The height of the output frame
- * @param timeMS The time in ms at which the frame has to be extracted
+ * and returns the frame as a bitmap. See getPixelsList() for more information.
*/
- Bitmap getPixels(String inputFile, int width, int height, long timeMS) {
- if (inputFile == null) {
- throw new IllegalArgumentException("Invalid input file");
- }
-
- /* Make width and height as even */
- final int newWidth = (width + 1) & 0xFFFFFFFE;
- final int newHeight = (height + 1) & 0xFFFFFFFE;
-
- /* Create a temp bitmap for resized thumbnails */
- Bitmap tempBitmap = null;
- if ((newWidth != width) || (newHeight != height)) {
- tempBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
- }
-
- IntBuffer rgb888 = IntBuffer.allocate(newWidth * newHeight * 4);
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- nativeGetPixels(inputFile, rgb888.array(), newWidth, newHeight, timeMS);
-
- if ((newWidth == width) && (newHeight == height)) {
- bitmap.copyPixelsFromBuffer(rgb888);
- } else {
- /* Create a temp bitmap to be used for resize */
- tempBitmap.copyPixelsFromBuffer(rgb888);
-
- /* Create a canvas to resize */
- final Canvas canvas = new Canvas(bitmap);
- canvas.drawBitmap(tempBitmap, new Rect(0, 0, newWidth, newHeight),
- new Rect(0, 0, width, height), sResizePaint);
- canvas.setBitmap(null);
- }
-
- if (tempBitmap != null) {
- tempBitmap.recycle();
- }
-
- return bitmap;
+ Bitmap getPixels(String filename, int width, int height, long timeMs,
+ int videoRotation) {
+ final Bitmap result[] = new Bitmap[1];
+ getPixelsList(filename, width, height, timeMs, timeMs, 1, new int[] {0},
+ new MediaItem.GetThumbnailListCallback() {
+ public void onThumbnail(Bitmap bitmap, int index) {
+ result[0] = bitmap;
+ }
+ }, videoRotation);
+ return result[0];
}
/**
* This method extracts a list of frame from the
* input file and returns the frame in bitmap array
*
- * @param filename The inputFile
- * @param width The width of the output frame
- * @param height The height of the output frame
+ * @param filename The input file name
+ * @param width The width of the output frame, before rotation
+ * @param height The height of the output frame, before rotation
* @param startMs The starting time in ms
* @param endMs The end time in ms
* @param thumbnailCount The number of frames to be extracted
* @param indices The indices of thumbnails wanted
* @param callback The callback used to pass back the bitmaps
- * from startMs to endMs
+ * @param videoRotation The rotation degree need to be done for the bitmap
*
* @return The frames as bitmaps in bitmap array
**/
@@ -3824,62 +3792,69 @@
long startMs, long endMs, int thumbnailCount, int[] indices,
final MediaItem.GetThumbnailListCallback callback,
final int videoRotation) {
- /* Make width and height as even */
- final int newWidth = (width + 1) & 0xFFFFFFFE;
- final int newHeight = (height + 1) & 0xFFFFFFFE;
- final int thumbnailSize = newWidth * newHeight;
- /* Create a temp bitmap for resized thumbnails */
- final Bitmap tempBitmap =
- (newWidth != width || newHeight != height)
- ? Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
+ // The decoder needs output width and height as even
+ final int decWidth = (width + 1) & 0xFFFFFFFE;
+ final int decHeight = (height + 1) & 0xFFFFFFFE;
+ final int thumbnailSize = decWidth * decHeight;
+
+ // We convert the decoder output (in int[]) to a bitmap by first
+ // copy it into an IntBuffer, then use Bitmap.copyPixelsFromBuffer to
+ // copy it to the bitmap.
+ final int[] decArray = new int[thumbnailSize];
+ final IntBuffer decBuffer = IntBuffer.allocate(thumbnailSize);
+
+ // If we need to resize and/or rotate the decoder output, we need a
+ // temporary bitmap to hold the decoded output.
+ final boolean needToMassage =
+ (decWidth != width || decHeight != height || videoRotation != 0);
+ final Bitmap tmpBitmap = needToMassage
+ ? Bitmap.createBitmap(decWidth, decHeight, Bitmap.Config.ARGB_8888)
: null;
- final int[] rgb888 = new int[thumbnailSize];
- final IntBuffer tmpBuffer = IntBuffer.allocate(thumbnailSize);
- nativeGetPixelsList(filename, rgb888, newWidth, newHeight,
- thumbnailCount, videoRotation, startMs, endMs, indices,
+ // The final output bitmap width/height may swap because of rotation.
+ final boolean needToSwapWH = (videoRotation == 90 || videoRotation == 270);
+ final int outWidth = needToSwapWH ? height : width;
+ final int outHeight = needToSwapWH ? width : height;
+
+ nativeGetPixelsList(filename, decArray, decWidth, decHeight,
+ thumbnailCount, startMs, endMs, indices,
new NativeGetPixelsListCallback() {
public void onThumbnail(int index) {
- Bitmap bitmap = Bitmap.createBitmap(
- width, height, Bitmap.Config.ARGB_8888);
- tmpBuffer.put(rgb888, 0, thumbnailSize);
- tmpBuffer.rewind();
+ // This is the bitmap we will output to the client
+ Bitmap outBitmap = Bitmap.createBitmap(
+ outWidth, outHeight, Bitmap.Config.ARGB_8888);
- if ((newWidth == width) && (newHeight == height)) {
- bitmap.copyPixelsFromBuffer(tmpBuffer);
+ // Copy int[] to IntBuffer
+ decBuffer.put(decArray, 0, thumbnailSize);
+ decBuffer.rewind();
+
+ if (!needToMassage) {
+ // We can directly read the decoded result to output bitmap
+ outBitmap.copyPixelsFromBuffer(decBuffer);
} else {
- /* Copy the out rgb buffer to temp bitmap */
- tempBitmap.copyPixelsFromBuffer(tmpBuffer);
+ // Copy the decoded result to an intermediate bitmap first
+ tmpBitmap.copyPixelsFromBuffer(decBuffer);
- /* Create a canvas to resize */
- final Canvas canvas = new Canvas(bitmap);
- canvas.drawBitmap(tempBitmap,
- new Rect(0, 0, newWidth, newHeight),
- new Rect(0, 0, width, height), sResizePaint);
-
- canvas.setBitmap(null);
+ // Create a canvas to resize/rotate the bitmap
+ // First scale the decoded bitmap to (0,0)-(1,1), rotate it
+ // with (0.5, 0.5) as center, then scale it to
+ // (outWidth, outHeight).
+ final Canvas canvas = new Canvas(outBitmap);
+ Matrix m = new Matrix();
+ float sx = 1f / decWidth;
+ float sy = 1f / decHeight;
+ m.postScale(sx, sy);
+ m.postRotate(videoRotation, 0.5f, 0.5f);
+ m.postScale(outWidth, outHeight);
+ canvas.drawBitmap(tmpBitmap, m, sResizePaint);
}
-
- if (videoRotation == 0) {
- callback.onThumbnail(bitmap, index);
- } else {
- Matrix mtx = new Matrix();
- mtx.postRotate(videoRotation);
- Bitmap rotatedBmp =
- Bitmap.createBitmap(bitmap, 0, 0, width, height, mtx, false);
- callback.onThumbnail(rotatedBmp, index);
-
- if (bitmap != null) {
- bitmap.recycle();
- }
- }
-
+ callback.onThumbnail(outBitmap, index);
}
});
- if (tempBitmap != null) {
- tempBitmap.recycle();
+ if (tmpBitmap != null) {
+ tmpBitmap.recycle();
}
}
@@ -3996,7 +3971,7 @@
long timeMS);
private native int nativeGetPixelsList(String fileName, int[] pixelArray,
- int width, int height, int nosofTN, int videoRotation, long startTimeMs,
+ int width, int height, int nosofTN, long startTimeMs,
long endTimeMs, int[] indices, NativeGetPixelsListCallback callback);
/**
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index 65a9e19..a862d00 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -606,7 +606,7 @@
public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {
if (getGeneratedImageClip() != null) {
return mMANativeHelper.getPixels(getGeneratedImageClip(),
- width, height,timeMs);
+ width, height, timeMs, 0);
} else {
return scaleImage(mFilename, width, height);
}
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 2ce857c..bbcdf57 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -293,7 +293,14 @@
throw new IllegalArgumentException("Invalid Dimensions");
}
- return mMANativeHelper.getPixels(super.getFilename(), width, height,timeMs);
+ if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+
+ return mMANativeHelper.getPixels(
+ getFilename(), width, height, timeMs, mVideoRotationDegree);
}
/*
@@ -318,8 +325,14 @@
throw new IllegalArgumentException("Invalid dimension");
}
- mMANativeHelper.getPixelsList(super.getFilename(), width,
- height, startMs, endMs, thumbnailCount, indices, callback,
+ if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+
+ mMANativeHelper.getPixelsList(getFilename(), width, height,
+ startMs, endMs, thumbnailCount, indices, callback,
mVideoRotationDegree);
}
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index f18dd88..2446c2f 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -1825,27 +1825,10 @@
if (mMediaItems.size() > 0) {
MediaItem mI = mMediaItems.get(0);
/*
- * Lets initialize the width for default aspect ratio i.e 16:9
+ * Keep aspect ratio of the image
*/
int height = 480;
- int width = 854;
- switch (mI.getAspectRatio()) {
- case MediaProperties.ASPECT_RATIO_3_2:
- width = 720;
- break;
- case MediaProperties.ASPECT_RATIO_4_3:
- width = 640;
- break;
- case MediaProperties.ASPECT_RATIO_5_3:
- width = 800;
- break;
- case MediaProperties.ASPECT_RATIO_11_9:
- width = 586;
- break;
- case MediaProperties.ASPECT_RATIO_16_9:
- case MediaProperties.ASPECT_RATIO_UNDEFINED:
- break;
- }
+ int width = mI.getWidth() * height / mI.getHeight();
Bitmap projectBitmap = null;
String filename = mI.getFilename();
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 4e73581..ed4e92e 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -185,7 +185,6 @@
M4OSA_UInt32 width,
M4OSA_UInt32 height,
M4OSA_UInt32 noOfThumbnails,
- M4OSA_UInt32 videoRotation,
jlong startTime,
jlong endTime,
jintArray indexArray,
@@ -292,7 +291,7 @@
(void *)videoEditor_release },
{"nativeGetPixels", "(Ljava/lang/String;[IIIJ)I",
(void*)videoEditor_getPixels },
- {"nativeGetPixelsList", "(Ljava/lang/String;[IIIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
+ {"nativeGetPixelsList", "(Ljava/lang/String;[IIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
(void*)videoEditor_getPixelsList },
{"getMediaProperties",
"(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;",
@@ -2286,7 +2285,6 @@
M4OSA_UInt32 width,
M4OSA_UInt32 height,
M4OSA_UInt32 noOfThumbnails,
- M4OSA_UInt32 videoRotation,
jlong startTime,
jlong endTime,
jintArray indexArray,
@@ -2330,6 +2328,10 @@
break;
}
env->CallVoidMethod(callback, mid, (jint)k);
+ if (env->ExceptionCheck()) {
+ err = M4ERR_ALLOC;
+ break;
+ }
}
env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
@@ -2340,7 +2342,7 @@
env->ReleaseStringUTFChars(path, pString);
}
- if (err != M4NO_ERROR) {
+ if (err != M4NO_ERROR && !env->ExceptionCheck()) {
jniThrowException(env, "java/lang/RuntimeException",\
"ThumbnailGetPixels32 failed");
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 7509239..c2c6715 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1078,6 +1078,11 @@
frames = mRemainingFrames;
}
+ int32_t waitCount = -1;
+ if (mUpdatePeriod || (!mMarkerReached && mMarkerPosition) || mLoopCount) {
+ waitCount = 1;
+ }
+
do {
audioBuffer.frameCount = frames;
@@ -1085,7 +1090,7 @@
// Calling obtainBuffer() with a wait count of 1
// limits wait time to WAIT_PERIOD_MS. This prevents from being
// stuck here not being able to handle timed events (position, markers, loops).
- status_t err = obtainBuffer(&audioBuffer, 1);
+ status_t err = obtainBuffer(&audioBuffer, waitCount);
if (err < NO_ERROR) {
if (err != TIMED_OUT) {
LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up.");
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index bd89ad8..50a41ca 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -108,6 +108,7 @@
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeStrongBinder(source->asBinder());
+ remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);
return reply.readInt32();
}
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 41f8593..19dedfc 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaScanner"
+#include <cutils/properties.h>
#include <utils/Log.h>
#include <media/mediascanner.h>
@@ -26,11 +27,14 @@
namespace android {
MediaScanner::MediaScanner()
- : mLocale(NULL) {
+ : mLocale(NULL), mSkipList(NULL), mSkipIndex(NULL) {
+ loadSkipList();
}
MediaScanner::~MediaScanner() {
setLocale(NULL);
+ free(mSkipList);
+ free(mSkipIndex);
}
void MediaScanner::setLocale(const char *locale) {
@@ -47,6 +51,33 @@
return mLocale;
}
+void MediaScanner::loadSkipList() {
+ mSkipList = (char *)malloc(PROPERTY_VALUE_MAX * sizeof(char));
+ if (mSkipList) {
+ property_get("testing.mediascanner.skiplist", mSkipList, "");
+ }
+ if (!mSkipList || (strlen(mSkipList) == 0)) {
+ free(mSkipList);
+ mSkipList = NULL;
+ return;
+ }
+ mSkipIndex = (int *)malloc(PROPERTY_VALUE_MAX * sizeof(int));
+ if (mSkipIndex) {
+ // dup it because strtok will modify the string
+ char *skipList = strdup(mSkipList);
+ if (skipList) {
+ char * path = strtok(skipList, ",");
+ int i = 0;
+ while (path) {
+ mSkipIndex[i++] = strlen(path);
+ path = strtok(NULL, ",");
+ }
+ mSkipIndex[i] = -1;
+ free(skipList);
+ }
+ }
+}
+
MediaScanResult MediaScanner::processDirectory(
const char *path, MediaScannerClient &client) {
int pathLength = strlen(path);
@@ -75,12 +106,39 @@
return result;
}
+bool MediaScanner::shouldSkipDirectory(char *path) {
+ if (path && mSkipList && mSkipIndex) {
+ int len = strlen(path);
+ int idx = 0;
+ // track the start position of next path in the comma
+ // separated list obtained from getprop
+ int startPos = 0;
+ while (mSkipIndex[idx] != -1) {
+ // no point to match path name if strlen mismatch
+ if ((len == mSkipIndex[idx])
+ // pick out the path segment from comma separated list
+ // to compare against current path parameter
+ && (strncmp(path, &mSkipList[startPos], len) == 0)) {
+ return true;
+ }
+ startPos += mSkipIndex[idx] + 1; // extra char for the delimiter
+ idx++;
+ }
+ }
+ return false;
+}
+
MediaScanResult MediaScanner::doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) {
// place to copy file or directory name
char* fileSpot = path + strlen(path);
struct dirent* entry;
+ if (shouldSkipDirectory(path)) {
+ LOGD("Skipping: %s", path);
+ return MEDIA_SCAN_RESULT_OK;
+ }
+
// Treat all files as non-media in directories that contain a ".nomedia" file
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index d41ab1b..ba076f5 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -20,8 +20,8 @@
#include <binder/IPCThreadState.h>
#include <media/AudioTrack.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -60,7 +60,7 @@
}
void AudioPlayer::setSource(const sp<MediaSource> &source) {
- CHECK_EQ(mSource, NULL);
+ CHECK(mSource == NULL);
mSource = source;
}
@@ -466,6 +466,8 @@
}
int64_t AudioPlayer::getRealTimeUsLocked() const {
+ CHECK(mStarted);
+ CHECK_NE(mSampleRate, 0);
return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 47224cc..07a46bd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1736,7 +1736,9 @@
modifyFlags(TEXT_RUNNING, SET);
}
- TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
+ TimeSource *ts =
+ ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
+ ? &mSystemTimeSource : mTimeSource;
if (mFlags & FIRST_FRAME) {
modifyFlags(FIRST_FRAME, CLEAR);
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 09f91f5..92e84c2 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -52,10 +52,7 @@
*post_id3_pos = 0;
}
- bool resync_from_head = false;
if (*inout_pos == 0) {
- resync_from_head = true;
-
// Skip an optional ID3 header if syncing at the very beginning
// of the datasource.
@@ -140,20 +137,22 @@
uint32_t header = U32_AT(tmp);
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ continue;
+ }
+
size_t frame_size;
- if ((match_header != 0 && (header & kMask) != (match_header & kMask))
- || !GetMPEGAudioFrameSize(header, &frame_size)) {
- if (resync_from_head) {
- // This isn't a valid mp3 file because it failed to detect
- // a header while a valid mp3 file should have a valid
- // header here.
- break;
- } else {
- ++pos;
- ++tmp;
- --remainingBytes;
- continue;
- }
+ int sample_rate, num_channels, bitrate;
+ if (!GetMPEGAudioFrameSize(
+ header, &frame_size,
+ &sample_rate, &num_channels, &bitrate)) {
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ continue;
}
LOGV("found possible 1st frame at %lld (header = 0x%08x)", pos, header);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index fb49d7b..9ab470b 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -50,7 +50,7 @@
// Treat time out as an error if we have not received any output
// buffers after 3 seconds.
-const static int64_t kBufferFilledEventTimeOutUs = 3000000000LL;
+const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL;
struct CodecInfo {
const char *mime;
@@ -2325,9 +2325,14 @@
{
CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)",
data1, data2);
- CHECK(mFilledBuffers.empty());
if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
+ // There is no need to check whether mFilledBuffers is empty or not
+ // when the OMX_EventPortSettingsChanged is not meant for reallocating
+ // the output buffers.
+ if (data1 == kPortIndexOutput) {
+ CHECK(mFilledBuffers.empty());
+ }
onPortSettingsChanged(data1);
} else if (data1 == kPortIndexOutput &&
(data2 == OMX_IndexConfigCommonOutputCrop ||
@@ -3220,7 +3225,7 @@
// for video encoding.
return mBufferFilled.wait(mLock);
}
- status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutUs);
+ status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
if (err != OK) {
CODEC_LOGE("Timed out waiting for output buffers: %d/%d",
countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 778c0b5..c74cb5a 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -283,8 +283,15 @@
return NULL;
}
+ sp<MetaData> fileMeta = mExtractor->getMetaData();
+
+ if (fileMeta == NULL) {
+ LOGV("extractor doesn't publish metadata, failed to initialize?");
+ return NULL;
+ }
+
int32_t drm = 0;
- if (mExtractor->getMetaData()->findInt32(kKeyIsDRM, &drm) && drm != 0) {
+ if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
LOGE("frame grab not allowed.");
return NULL;
}
@@ -320,7 +327,7 @@
const void *data;
uint32_t type;
size_t dataSize;
- if (mExtractor->getMetaData()->findData(kKeyAlbumArt, &type, &data, &dataSize)
+ if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
&& mAlbumArt == NULL) {
mAlbumArt = new MediaAlbumArt;
mAlbumArt->mSize = dataSize;
@@ -387,6 +394,11 @@
void StagefrightMetadataRetriever::parseMetaData() {
sp<MetaData> meta = mExtractor->getMetaData();
+ if (meta == NULL) {
+ LOGV("extractor doesn't publish metadata, failed to initialize?");
+ return;
+ }
+
struct Map {
int from;
int to;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 50dd804..306f1f6 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "SurfaceMediaSource"
#include <media/stagefright/SurfaceMediaSource.h>
@@ -458,6 +458,10 @@
LOGV("queueBuffer");
Mutex::Autolock lock(mMutex);
+ *outWidth = mDefaultWidth;
+ *outHeight = mDefaultHeight;
+ *outTransform = 0;
+
if (bufIndex < 0 || bufIndex >= mBufferCount) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, bufIndex);
@@ -518,9 +522,6 @@
// buffer is available
onFrameReceivedLocked();
- *outWidth = mDefaultWidth;
- *outHeight = mDefaultHeight;
- *outTransform = 0;
return OK;
}
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 3ef7b71..ffa3356 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -93,7 +93,7 @@
void advance();
void reset();
- void seek(int64_t seekTimeUs);
+ void seek(int64_t seekTimeUs, bool seekToKeyFrame);
const mkvparser::Block *block() const;
int64_t blockTimeUs() const;
@@ -137,6 +137,7 @@
sp<MatroskaExtractor> mExtractor;
size_t mTrackIndex;
Type mType;
+ bool mIsAudio;
BlockIterator mBlockIter;
size_t mNALSizeLen; // for type AVC
@@ -156,6 +157,7 @@
: mExtractor(extractor),
mTrackIndex(index),
mType(OTHER),
+ mIsAudio(false),
mBlockIter(mExtractor.get(),
mExtractor->mTracks.itemAt(index).mTrackNum),
mNALSizeLen(0) {
@@ -164,6 +166,8 @@
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
+ mIsAudio = !strncasecmp("audio/", mime, 6);
+
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
mType = AVC;
@@ -299,7 +303,7 @@
} while (!eos() && block()->GetTrackNumber() != mTrackNum);
}
-void BlockIterator::seek(int64_t seekTimeUs) {
+void BlockIterator::seek(int64_t seekTimeUs, bool seekToKeyFrame) {
Mutex::Autolock autoLock(mExtractor->mLock);
mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
@@ -311,8 +315,10 @@
}
while (!eos() && block()->GetTrackNumber() != mTrackNum);
- while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
- advance_l();
+ if (seekToKeyFrame) {
+ while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
+ advance_l();
+ }
}
}
@@ -396,7 +402,11 @@
if (options && options->getSeekTo(&seekTimeUs, &mode)
&& !mExtractor->isLiveStreaming()) {
clearPendingFrames();
- mBlockIter.seek(seekTimeUs);
+
+ // Apparently keyframe indication in audio tracks is unreliable,
+ // fortunately in all our currently supported audio encodings every
+ // frame is effectively a keyframe.
+ mBlockIter.seek(seekTimeUs, !mIsAudio);
}
again:
@@ -537,6 +547,13 @@
return;
}
+#if 0
+ const mkvparser::SegmentInfo *info = mSegment->GetInfo();
+ LOGI("muxing app: %s, writing app: %s",
+ info->GetMuxingAppAsUTF8(),
+ info->GetWritingAppAsUTF8());
+#endif
+
addTracks();
}
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index d663602..d7bb703 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -156,8 +156,6 @@
eglDestroySurface(mEglDisplay, mEglSurface);
}
if (mEglDisplay != EGL_NO_DISPLAY) {
- eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
eglTerminate(mEglDisplay);
}
ASSERT_EQ(EGL_SUCCESS, eglGetError());
@@ -461,6 +459,7 @@
// The following call dequeues and queues the buffer
eglSwapBuffers(mEglDisplay, mEglSurface);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
glDisable(GL_SCISSOR_TEST);
}
@@ -796,7 +795,12 @@
LOGV("framesCount = %d", nFramesCount);
}
- ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL));
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = EGL_NO_SURFACE;
+
writer.stop();
}
// Test to examine whether we can render GL buffers in to the surface
@@ -875,7 +879,12 @@
LOGV("framesCount = %d", nFramesCount);
}
- ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL));
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = EGL_NO_SURFACE;
+
LOGV("Stopping MediaRecorder...");
CHECK_EQ(OK, mr->stop());
mr.clear();
@@ -913,7 +922,12 @@
LOGV("framesCount = %d", nFramesCount);
}
- ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL));
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = EGL_NO_SURFACE;
+
LOGV("Stopping MediaRecorder...");
CHECK_EQ(OK, mr->stop());
mr.clear();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index b1ad315..b1d049e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -95,6 +95,25 @@
return audioEncoderMap.get(audioEncoder);
}
+ public static int getMinFrameRateForCodec(int codec) {
+ return getMinOrMaxFrameRateForCodec(codec, false);
+ }
+
+ public static int getMaxFrameRateForCodec(int codec) {
+ return getMinOrMaxFrameRateForCodec(codec, true);
+ }
+
+ private static int getMinOrMaxFrameRateForCodec(int codec, boolean max) {
+ for (VideoEncoderCap cap: videoEncoders) {
+ if (cap.mCodec == codec) {
+ if (max) return cap.mMaxFrameRate;
+ else return cap.mMinFrameRate;
+ }
+ }
+ // Should never reach here
+ throw new IllegalArgumentException("Unsupported video codec " + codec);
+ }
+
private MediaProfileReader() {} // Don't call me
private static void initVideoEncoderMap() {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
index 154f691..d5b67aa 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
@@ -657,7 +657,7 @@
public void testThumbnailListForH264WVGAWithCount() throws Exception {
final String videoItemFilename = INPUT_FILE_PATH +
"H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int tnCount = 100;
+ final int tnCount = 70;
final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
final MediaVideoItem mediaVideoItem =
mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index 82df6690..796b52c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -247,7 +247,9 @@
mCamera.unlock();
mRecorder.setCamera(mCamera);
Thread.sleep(1000);
- recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.H263,
+ int codec = MediaRecorder.VideoEncoder.H263;
+ int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
+ recordVideo(frameRate, 352, 288, codec,
MediaRecorder.OutputFormat.THREE_GPP,
MediaNames.RECORDED_PORTRAIT_H263, true);
mCamera.lock();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 0810643..0b887b9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -26,6 +26,7 @@
import android.hardware.Camera.PreviewCallback;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
+import android.media.EncoderCapabilities.VideoEncoderCap;
import android.os.ConditionVariable;
import android.os.Looper;
import android.os.SystemClock;
@@ -35,6 +36,7 @@
import android.util.Log;
import android.view.SurfaceHolder;
+import java.util.List;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -48,11 +50,12 @@
import android.media.MediaMetadataRetriever;
import com.android.mediaframeworktest.MediaProfileReader;
-import android.hardware.Camera.PreviewCallback;
-
/**
* Junit / Instrumentation - performance measurement for media player and
* recorder
+ *
+ * FIXME:
+ * Add tests on H264 video encoder
*/
public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
@@ -81,6 +84,8 @@
private static int DECODER_LIMIT = 150;
private static int CAMERA_LIMIT = 80;
+ private static List<VideoEncoderCap> videoEncoders = MediaProfileReader.getVideoEncoders();
+
Camera mCamera;
public MediaPlayerPerformance() {
@@ -369,8 +374,10 @@
File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true));
output.write("H263 video record only\n");
+ int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
+ assertTrue("H263 video recording frame rate", frameRate != -1);
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
- assertTrue(stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
+ assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true));
getMemoryWriteToLog(output, i);
}
@@ -389,8 +396,10 @@
File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true));
output.write("MPEG4 video record only\n");
+ int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.MPEG_4_SP);
+ assertTrue("MPEG4 video recording frame rate", frameRate != -1);
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
- assertTrue(stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
+ assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true));
getMemoryWriteToLog(output, i);
}
@@ -409,9 +418,11 @@
File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true));
+ int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
+ assertTrue("H263 video recording frame rate", frameRate != -1);
output.write("Audio and h263 video record\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
- assertTrue(stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
+ assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false));
getMemoryWriteToLog(output, i);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index ae0589c..e6177ba 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -205,7 +205,7 @@
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(filename);
- mRecorder.setVideoFrameRate(20);
+ mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate);
mRecorder.setVideoSize(176,144);
Log.v(TAG, "setEncoder");
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
@@ -269,7 +269,7 @@
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(filename);
- mRecorder.setVideoFrameRate(20);
+ mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate);
mRecorder.setVideoSize(176,144);
Log.v(TAG, "Media recorder setEncoder");
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index ca62908..1e43195 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -148,10 +148,13 @@
if (egl_tls_t::logNoContextCall()) {
LOGE("call to OpenGL ES API with no current context "
"(logged once per thread)");
- LOGE("call stack before error:");
- CallStack stack;
- stack.update();
- stack.dump();
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.callstack", value, "0");
+ if (atoi(value)) {
+ CallStack stack;
+ stack.update();
+ stack.dump();
+ }
}
return 0;
}
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index 961a61e..f3c8d2c 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -14,9 +14,13 @@
** limitations under the License.
*/
+#include <stdlib.h>
#include <pthread.h>
#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/CallStack.h>
#include <EGL/egl.h>
@@ -69,6 +73,13 @@
if (tls->error != error) {
LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
tls->error = error;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.callstack", value, "0");
+ if (atoi(value)) {
+ CallStack stack;
+ stack.update();
+ stack.dump();
+ }
}
}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
index d17aae6..babddb1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
index 5a89d76..56cd6f9 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
new file mode 100644
index 0000000..23ce001
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
new file mode 100644
index 0000000..d0754a39
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
index 1ad16f7..652f66f 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
index 6e806ee..288d818 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
index 35d0a06..0f0cbf1 100644
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
index 9490833..bf1bad5 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
index 0ff3efd..320d92d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
new file mode 100644
index 0000000..b58e4dc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
new file mode 100644
index 0000000..604eb75
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
index 0352aca..6f4d658 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
index 7376085..10e4fd2 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
index 79da092..5e8a116 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
index 6455423..cf9bd8e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
index bfa8bb4..8eee4d9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
new file mode 100644
index 0000000..5e67545
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
new file mode 100644
index 0000000..e56aeda
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
new file mode 100644
index 0000000..1d097c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
index 507ee22..5bae56d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..efac368
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
new file mode 100644
index 0000000..b37dc39
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true"
+ android:drawable="@drawable/ic_notify_quicksettings_pressed" />
+ <item android:drawable="@drawable/ic_notify_quicksettings_normal" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
new file mode 100644
index 0000000..d683af9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_selected="true" />
+ <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+ <item android:drawable="@*android:color/transparent"/>
+</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 4b2468a..eae3e52 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -21,7 +21,9 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
- android:layout_width="wrap_content">
+ android:layout_width="wrap_content"
+ android:paddingLeft="@dimen/status_bar_recents_item_padding"
+ android:paddingRight="@dimen/status_bar_recents_item_padding">
<RelativeLayout android:id="@+id/recent_item"
android:layout_gravity="bottom"
@@ -35,12 +37,11 @@
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
- android:scaleType="center"
- android:background="@drawable/recents_thumbnail_bg">
+ android:background="@drawable/recents_thumbnail_bg"
+ android:foreground="@drawable/recents_thumbnail_fg">
<ImageView android:id="@+id/app_thumbnail_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index a327d42..b14ef595 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -21,7 +21,9 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
- android:layout_width="match_parent">
+ android:layout_width="match_parent"
+ android:paddingTop="@dimen/status_bar_recents_item_padding"
+ android:paddingBottom="@dimen/status_bar_recents_item_padding">
<RelativeLayout android:id="@+id/recent_item"
android:layout_height="wrap_content"
@@ -33,12 +35,11 @@
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
- android:scaleType="center"
- android:background="@drawable/recents_thumbnail_bg">
+ android:background="@drawable/recents_thumbnail_bg"
+ android:foreground="@drawable/recents_thumbnail_fg">
<ImageView android:id="@+id/app_thumbnail_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
index d235859..5e254e8 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
@@ -89,9 +89,10 @@
<TextView android:id="@+id/time_solid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:singleLine="true"
android:textSize="40sp"
- android:textColor="#ff525e79" />
+ />
</com.android.systemui.statusbar.tablet.HoloClock>
<TextView
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 0f45bcd..f4be651 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -30,11 +30,11 @@
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
- android:background="@drawable/recents_thumbnail_bg">
+ android:background="@drawable/recents_thumbnail_bg"
+ android:foreground="@drawable/recents_thumbnail_fg">
<ImageView android:id="@+id/app_thumbnail_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f3d0bee..a63893e 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -72,13 +72,12 @@
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
- android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:singleLine="true"
android:paddingRight="6dip"
android:textSize="16sp"
- android:textStyle="bold"
android:gravity="center_vertical|left"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index b5274a3..0b3fb98 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -34,9 +34,7 @@
android:paddingRight="3dp"
>
<com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
- android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
- android:textColor="@android:color/holo_blue_light"
- android:textStyle="normal"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
@@ -58,22 +56,24 @@
android:textColor="?android:attr/textColorSecondary"
/>
-->
+
<ImageView android:id="@+id/settings_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@id/date"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:src="@drawable/ic_sysbar_quicksettings"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:src="@drawable/ic_notify_quicksettings"
/>
+
<ImageView android:id="@+id/clear_all_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
android:src="@drawable/ic_notify_clear"
- />
+ />
</RelativeLayout>
<View
diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml
index 277626e..6b6fd4d 100644
--- a/packages/SystemUI/res/values-hdpi/dimens.xml
+++ b/packages/SystemUI/res/values-hdpi/dimens.xml
@@ -16,10 +16,6 @@
*/
-->
<resources>
- <!-- padding of pressed drawable for recents thumbnails (should be the same on left, right,
- top, and bottom -->
- <dimen name="recents_thumbnail_bg_press_padding">3px</dimen>
-
<!-- thickness (height) of each notification row, including any separators or padding -->
<!-- Note: this is 64dip + 1px divider = 97px. -->
<dimen name="notification_height">97px</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index ca74b8b..32ebc80 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -21,7 +21,7 @@
<!-- Recent Applications parameters -->
<!-- How far the thumbnail for a recent app appears from left edge -->
- <dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen>
+ <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen>
<!-- How far the thumbnail for a recent app appears from top edge -->
<dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen>
<!-- Padding for text descriptions -->
@@ -32,4 +32,6 @@
<dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
<!-- Margin between recents container and glow on the right -->
<dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
+ <!-- Padding between recents items -->
+ <dimen name="status_bar_recents_item_padding">2dip</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml
deleted file mode 100644
index d16d549b..0000000
--- a/packages/SystemUI/res/values-mdpi/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-<resources>
- <!-- padding of pressed drawable for recents thumbnails (should be the same on left, right,
- top, and bottom -->
- <dimen name="recents_thumbnail_bg_press_padding">2px</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml
index b89a610..2bafd30 100644
--- a/packages/SystemUI/res/values-port/dimens.xml
+++ b/packages/SystemUI/res/values-port/dimens.xml
@@ -22,9 +22,11 @@
<!-- Padding for text descriptions -->
<dimen name="status_bar_recents_text_description_padding">8dp</dimen>
<!-- Width of application label text -->
- <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+ <dimen name="status_bar_recents_app_label_width">88dip</dimen>
<!-- Left margin of application label text -->
- <dimen name="status_bar_recents_app_label_left_margin">8dip</dimen>
+ <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
<!-- Margin between recents container and glow on the right -->
<dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
+ <!-- Padding between recents items -->
+ <dimen name="status_bar_recents_item_padding">0dip</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ad236b7..3d49cd1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -40,6 +40,12 @@
<item name="android:textColor">#FFFFFFFF</item>
</style>
+ <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">@android:color/holo_blue_light</item>
+ </style>
+
<style name="Animation" />
<style name="Animation.ShirtPocketPanel">
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 43905dd..f7afe3a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -85,7 +85,6 @@
private View mRecentsGlowView;
private ViewGroup mRecentsContainer;
private Bitmap mDefaultThumbnailBackground;
- private BitmapDrawable mPressedDrawable;
private boolean mShowing;
private Choreographer mChoreo;
@@ -96,11 +95,13 @@
/* package */ final class ActivityDescription {
final ActivityManager.RecentTaskInfo recentTaskInfo;
final ResolveInfo resolveInfo;
- int taskId; // application task id for curating apps
- Intent intent; // launch intent for application
+ final int taskId; // application task id for curating apps
+ final int persistentTaskId; // persistent id
+ final Intent intent; // launch intent for application
+ final String packageName; // used to override animations (see onClick())
+ final int position; // position in list
+
Matrix matrix; // arbitrary rotation matrix to correct orientation
- String packageName; // used to override animations (see onClick())
- int position; // position in list
private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
private Drawable mIcon; // application package icon
@@ -108,11 +109,12 @@
public ActivityDescription(ActivityManager.RecentTaskInfo _recentInfo,
ResolveInfo _resolveInfo, Intent _intent,
- int _id, int _pos, String _packageName) {
+ int _pos, String _packageName) {
recentTaskInfo = _recentInfo;
resolveInfo = _resolveInfo;
intent = _intent;
- taskId = _id;
+ taskId = _recentInfo.id;
+ persistentTaskId = _recentInfo.persistentId;
position = _pos;
packageName = _packageName;
}
@@ -184,12 +186,12 @@
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
- StateListDrawable thumbnailForegroundDrawable = new StateListDrawable();
+ /* StateListDrawable thumbnailForegroundDrawable = new StateListDrawable();
thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_pressed },
mPressedDrawable);
thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_selected },
mPressedDrawable);
- ((FrameLayout)holder.thumbnailView).setForeground(thumbnailForegroundDrawable);
+ ((FrameLayout)holder.thumbnailView).setForeground(thumbnailForegroundDrawable);*/
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
@@ -352,18 +354,6 @@
mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
-
- // Render the pressed state (setting the 9 patch drawable directly causes padding issues)
- int bgPadding = (int) res.getDimension(R.dimen.recents_thumbnail_bg_press_padding);
- Bitmap pressedOverlay = Bitmap.createBitmap(
- width + 2 * bgPadding, height + 2 * bgPadding, Bitmap.Config.ARGB_8888);
- c.setBitmap(pressedOverlay);
-
- Drawable pressedDrawable9Patch = res.getDrawable(R.drawable.recents_thumbnail_bg_press);
- pressedDrawable9Patch.getCurrent().setBounds(
- 0, 0, pressedOverlay.getWidth(), pressedOverlay.getHeight());
- pressedDrawable9Patch.draw(c);
- mPressedDrawable = new BitmapDrawable(res, pressedOverlay);
}
@Override
@@ -496,17 +486,17 @@
final String title = info.loadLabel(pm).toString();
// Drawable icon = info.loadIcon(pm);
Drawable icon = getFullResIcon(resolveInfo, pm);
- int id = recentInfo.id;
if (title != null && title.length() > 0 && icon != null) {
- if (DEBUG) Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title);
+ if (DEBUG) Log.v(TAG, "creating activity desc for id="
+ + recentInfo.id + ", label=" + title);
ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(
recentInfo.persistentId);
ActivityDescription item = new ActivityDescription(recentInfo,
- resolveInfo, intent, id, index, info.packageName);
+ resolveInfo, intent, index, info.packageName);
activityDescriptions.add(item);
++index;
} else {
- if (DEBUG) Log.v(TAG, "SKIPPING item " + id);
+ if (DEBUG) Log.v(TAG, "SKIPPING item " + recentInfo.id);
}
}
}
@@ -727,7 +717,7 @@
// the task.
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
- am.removeTask(ad.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
}
private void startApplicationDetailsActivity(String packageName) {
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 8be250b..ee9aa41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1174,7 +1174,6 @@
case MSG_OPEN_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "opening recents panel");
if (mRecentsPanel != null) {
- disable(StatusBarManager.DISABLE_BACK);
mRecentsPanel.setVisibility(View.VISIBLE);
mRecentsPanel.show(true, true);
}
@@ -1182,7 +1181,6 @@
case MSG_CLOSE_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "closing recents panel");
if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
- disable(StatusBarManager.DISABLE_NONE);
mRecentsPanel.show(false, true);
}
break;
@@ -1797,30 +1795,34 @@
pw.println(" [" + i + "] icon=" + ic);
}
- pw.println("see the logcat for a dump of the views we have created.");
- // must happen on ui thread
- mHandler.post(new Runnable() {
- public void run() {
- mStatusBarView.getLocationOnScreen(mAbsPos);
- Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mStatusBarView.getWidth() + "x"
- + mStatusBarView.getHeight());
- mStatusBarView.debug();
+ if (false) {
+ pw.println("see the logcat for a dump of the views we have created.");
+ // must happen on ui thread
+ mHandler.post(new Runnable() {
+ public void run() {
+ mStatusBarView.getLocationOnScreen(mAbsPos);
+ Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ + ") " + mStatusBarView.getWidth() + "x"
+ + mStatusBarView.getHeight());
+ mStatusBarView.debug();
- mExpandedView.getLocationOnScreen(mAbsPos);
- Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mExpandedView.getWidth() + "x"
- + mExpandedView.getHeight());
- mExpandedView.debug();
+ mExpandedView.getLocationOnScreen(mAbsPos);
+ Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ + ") " + mExpandedView.getWidth() + "x"
+ + mExpandedView.getHeight());
+ mExpandedView.debug();
- mTrackingView.getLocationOnScreen(mAbsPos);
- Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mTrackingView.getWidth() + "x"
- + mTrackingView.getHeight());
- mTrackingView.debug();
- }
- });
+ mTrackingView.getLocationOnScreen(mAbsPos);
+ Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ + ") " + mTrackingView.getWidth() + "x"
+ + mTrackingView.getHeight());
+ mTrackingView.debug();
+ }
+ });
+ }
}
+
+ mNetworkController.dump(fd, pw, args);
}
void onBarViewAttached() {
@@ -1829,7 +1831,6 @@
Drawable bg;
/// ---------- Tracking View --------------
- pixelFormat = PixelFormat.RGBX_8888;
bg = mTrackingView.getBackground();
if (bg != null) {
pixelFormat = bg.getOpacity();
@@ -1843,7 +1844,10 @@
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- pixelFormat);
+ PixelFormat.OPAQUE);
+ if (ActivityManager.isHighEndGfx(mDisplay)) {
+ lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ }
// lp.token = mStatusBarView.getWindowToken();
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("TrackingView");
@@ -1870,6 +1874,9 @@
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_DITHER
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ if (ActivityManager.isHighEndGfx(mDisplay)) {
+ lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ }
lp.format = pixelFormat;
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("StatusBarExpanded");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index d3f9525..c19550b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -22,11 +22,9 @@
import android.content.IntentFilter;
import android.text.format.DateFormat;
import android.util.AttributeSet;
-import android.util.Slog;
-import android.widget.TextView;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
+import android.widget.TextView;
import com.android.systemui.R;
@@ -42,9 +40,10 @@
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_TIME_TICK)
- || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_TIME_TICK.equals(action)
+ || Intent.ACTION_TIME_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
updateClock();
}
}
@@ -118,6 +117,7 @@
// Register for Intent broadcasts for the clock and battery
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
mContext.registerReceiver(mIntentReceiver, filter, null, null);
updateClock();
@@ -127,4 +127,3 @@
}
}
}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 3c85814..3b097af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -296,6 +296,7 @@
}
mServiceState = state;
updateTelephonySignalStrength();
+ updateDataNetType();
updateDataIcon();
refreshViews();
}
@@ -448,6 +449,7 @@
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
if (mHspaDataDistinguishable) {
mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
@@ -831,7 +833,12 @@
mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
mContentDescriptionCombinedSignal = mHasMobileDataFeature
? mContentDescriptionDataType : mContentDescriptionWifi;
- mDataTypeIconId = 0;
+
+ if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+ } else {
+ mDataTypeIconId = 0;
+ }
}
if (DEBUG) {
@@ -969,6 +976,7 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Network Controller state:");
pw.println(" - telephony ------");
pw.print(" mHspaDataDistinguishable=");
pw.println(mHspaDataDistinguishable);
@@ -982,6 +990,10 @@
pw.println(mDataState);
pw.print(" mDataActivity=");
pw.println(mDataActivity);
+ pw.print(" mDataNetType=");
+ pw.print(mDataNetType);
+ pw.print("/");
+ pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
pw.print(" mServiceState=");
pw.println(mServiceState);
pw.print(" mNetworkName=");
@@ -989,7 +1001,7 @@
pw.print(" mNetworkNameDefault=");
pw.println(mNetworkNameDefault);
pw.print(" mNetworkNameSeparator=");
- pw.println(mNetworkNameSeparator);
+ pw.println(mNetworkNameSeparator.replace("\n","\\n"));
pw.print(" mPhoneSignalIconId=0x");
pw.print(Integer.toHexString(mPhoneSignalIconId));
pw.print("/");
@@ -1060,7 +1072,7 @@
}
private String getResourceName(int resId) {
- if (resId == 0) {
+ if (resId != 0) {
final Resources res = mContext.getResources();
try {
return res.getResourceName(resId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index e287b7a..06798c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -20,7 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -37,12 +37,12 @@
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
-import java.util.HashSet;
+import java.util.HashMap;
public class NotificationRowLayout extends ViewGroup implements SwipeHelper.Callback {
private static final String TAG = "NotificationRowLayout";
private static final boolean DEBUG = false;
- private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
+ private static final boolean SLOW_ANIMATIONS = DEBUG;
private static final boolean ANIMATE_LAYOUT = true;
@@ -54,8 +54,8 @@
int mRowHeight = 0;
int mHeight = 0;
- HashSet<View> mAppearingViews = new HashSet<View>();
- HashSet<View> mDisappearingViews = new HashSet<View>();
+ HashMap<View, ValueAnimator> mAppearingViews = new HashMap<View, ValueAnimator>();
+ HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
private SwipeHelper mSwipeHelper;
@@ -166,8 +166,6 @@
final View childF = child;
if (ANIMATE_LAYOUT) {
- mAppearingViews.add(child);
-
child.setPivotY(0);
final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
alphaFade.setDuration(APPEAR_ANIM_LEN);
@@ -178,7 +176,11 @@
requestLayout(); // pick up any final changes in position
}
});
+
alphaFade.start();
+
+ mAppearingViews.put(child, alphaFade);
+
requestLayout(); // start the container animation
}
}
@@ -187,27 +189,27 @@
public void removeView(View child) {
final View childF = child;
if (ANIMATE_LAYOUT) {
- if (mAppearingViews.contains(child)) {
+ if (mAppearingViews.containsKey(child)) {
mAppearingViews.remove(child);
}
- mDisappearingViews.add(child);
-
child.setPivotY(0);
final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f);
+ alphaFade.setDuration(DISAPPEAR_ANIM_LEN);
alphaFade.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (DEBUG) Slog.d(TAG, "actually removing child: " + childF);
NotificationRowLayout.super.removeView(childF);
- childF.setAlpha(1f);
mDisappearingViews.remove(childF);
requestLayout(); // pick up any final changes in position
}
});
- alphaFade.setDuration(DISAPPEAR_ANIM_LEN);
alphaFade.start();
+
+ mDisappearingViews.put(child, alphaFade);
+
requestLayout(); // start the container animation
} else {
super.removeView(child);
@@ -246,7 +248,7 @@
if (child.getVisibility() == GONE) {
continue;
}
- if (mDisappearingViews.contains(child)) {
+ if (mDisappearingViews.containsKey(child)) {
continue;
}
numRows++;
@@ -304,14 +306,19 @@
if (child.getVisibility() == GONE) {
continue;
}
- float alpha = child.getAlpha();
- if (alpha > 1.0f) {
- if (DEBUG) {
- Slog.w(TAG, "alpha=" + alpha + " > 1!!! " + child);
- }
- alpha = 1f;
+ float progress = 1.0f;
+ if (mDisappearingViews.containsKey(child)) {
+ progress = 1.0f - mDisappearingViews.get(child).getAnimatedFraction();
+ } else if (mAppearingViews.containsKey(child)) {
+ progress = 1.0f - mAppearingViews.get(child).getAnimatedFraction();
}
- final int thisRowHeight = (int)(alpha * mRowHeight);
+ if (progress > 1.0f) {
+ if (DEBUG) {
+ Slog.w(TAG, "progress=" + progress + " > 1!!! " + child);
+ }
+ progress = 1f;
+ }
+ final int thisRowHeight = (int)(progress * mRowHeight);
if (DEBUG) {
Slog.d(TAG, String.format(
"laying out child #%d: (0, %d, %d, %d) h=%d",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index 5911378..e406a0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -218,15 +218,16 @@
private View createInputMethodItem(
final InputMethodInfo imi, final InputMethodSubtype subtype) {
- CharSequence subtypeName = getSubtypeName(imi, subtype);
- CharSequence imiName = getIMIName(imi);
- Drawable icon = getSubtypeIcon(imi, subtype);
- View view = View.inflate(mContext, R.layout.status_bar_input_methods_item, null);
- ImageView subtypeIcon = (ImageView)view.findViewById(R.id.item_icon);
- TextView itemTitle = (TextView)view.findViewById(R.id.item_title);
- TextView itemSubtitle = (TextView)view.findViewById(R.id.item_subtitle);
- ImageView settingsIcon = (ImageView)view.findViewById(R.id.item_settings_icon);
- View subtypeView = view.findViewById(R.id.item_subtype);
+ final CharSequence subtypeName = subtype.overridesImplicitlyEnabledSubtype()
+ ? null : getSubtypeName(imi, subtype);
+ final CharSequence imiName = getIMIName(imi);
+ final Drawable icon = getSubtypeIcon(imi, subtype);
+ final View view = View.inflate(mContext, R.layout.status_bar_input_methods_item, null);
+ final ImageView subtypeIcon = (ImageView)view.findViewById(R.id.item_icon);
+ final TextView itemTitle = (TextView)view.findViewById(R.id.item_title);
+ final TextView itemSubtitle = (TextView)view.findViewById(R.id.item_subtitle);
+ final ImageView settingsIcon = (ImageView)view.findViewById(R.id.item_settings_icon);
+ final View subtypeView = view.findViewById(R.id.item_subtype);
if (subtypeName == null) {
itemTitle.setText(imiName);
itemSubtitle.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index b4c480b..39011d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -301,6 +301,7 @@
mRecentsPanel = (RecentsPanelView) View.inflate(context,
R.layout.status_bar_recent_panel, null);
mRecentsPanel.setVisibility(View.GONE);
+ mRecentsPanel.setSystemUiVisibility(View.STATUS_BAR_DISABLE_BACK);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
mRecentsPanel));
mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
@@ -436,6 +437,13 @@
sb.setHandler(mHandler);
+ // Sanity-check that someone hasn't set up the config wrong and asked for a navigation bar
+ // on a tablet that has only the system bar
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_showNavigationBar)) {
+ throw new RuntimeException("Tablet device cannot show navigation bar and system bar");
+ }
+
mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);
// layout transitions for the status bar's contents
mBarContentsLayoutTransition = new LayoutTransition();
@@ -705,7 +713,6 @@
case MSG_OPEN_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "opening recents panel");
if (mRecentsPanel != null) {
- disable(StatusBarManager.DISABLE_BACK);
mRecentsPanel.setVisibility(View.VISIBLE);
mRecentsPanel.show(true, true);
}
@@ -713,7 +720,6 @@
case MSG_CLOSE_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "closing recents panel");
if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
- disable(StatusBarManager.DISABLE_NONE);
mRecentsPanel.show(false, true);
}
break;
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index 74dde9c..2fcf1dc3 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -127,6 +127,15 @@
*/
abstract public void cleanUp();
+ /**
+ * These were added to support FaceLock because the KeyguardViewManager needs to tell the
+ * LockPatternKeyguardView when to bind and and unbind with FaceLock service. Although
+ * implemented in LockPatternKeyguardView, these are not implemented in anything else
+ * derived from KeyguardViewBase
+ */
+ abstract public void bindToFaceLock();
+ abstract public void stopAndUnbindFromFaceLock();
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index c1f1151..cbf1c90 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -24,6 +24,7 @@
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Canvas;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +32,8 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.graphics.Color;
+
/**
* Manages creating, showing, hiding and resetting the keyguard. Calls back
* via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
@@ -98,7 +101,9 @@
if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
Resources res = mContext.getResources();
- boolean enableScreenRotation = res.getBoolean(R.bool.config_enableLockScreenRotation);
+ boolean enableScreenRotation =
+ SystemProperties.getBoolean("lockscreen.rot_override",false)
+ || res.getBoolean(R.bool.config_enableLockScreenRotation);
if (mKeyguardHost == null) {
if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
@@ -160,6 +165,7 @@
mKeyguardView.onScreenTurnedOn();
}
}
+
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.setVisibility(View.VISIBLE);
mKeyguardView.requestFocus();
@@ -194,6 +200,9 @@
mScreenOn = false;
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOff();
+
+ // When screen is turned off, need to unbind from FaceLock service if using FaceLock
+ mKeyguardView.stopAndUnbindFromFaceLock();
}
}
@@ -202,6 +211,9 @@
mScreenOn = true;
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOn();
+
+ // When screen is turned on, need to bind to FaceLock service if we are using FaceLock
+ mKeyguardView.bindToFaceLock();
}
}
@@ -238,6 +250,13 @@
*/
public synchronized void hide() {
if (DEBUG) Log.d(TAG, "hide()");
+
+ if (mKeyguardView != null) {
+ // When view is hidden, need to unbind from FaceLock service if we are using FaceLock
+ // e.g., when device becomes unlocked
+ mKeyguardView.stopAndUnbindFromFaceLock();
+ }
+
if (mKeyguardHost != null) {
mKeyguardHost.setVisibility(View.GONE);
// Don't do this right away, so we can let the view continue to animate
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 2a34f18..64a9677 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -1202,12 +1202,15 @@
// showing secure lockscreen; disable expanding.
flags |= StatusBarManager.DISABLE_EXPAND;
}
+ if (isSecure()) {
+ // showing secure lockscreen; disable ticker.
+ flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER;
+ }
}
if (DEBUG) {
- Log.d(TAG,
- "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
- + " isSecure=" + isSecure() + " --> flags=" + flags);
+ Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
+ + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
}
mStatusBarManager.disable(flags);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 62abf20..1d311d6 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -18,6 +18,8 @@
import com.android.internal.R;
import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
+import com.android.internal.policy.IFaceLockCallback;
+import com.android.internal.policy.IFaceLockInterface;
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockScreenWidgetCallback;
@@ -32,16 +34,20 @@
import android.accounts.OperationCanceledException;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.telephony.TelephonyManager;
@@ -56,6 +62,7 @@
import java.io.IOException;
+
/**
* The host view for all of the screens of the pattern unlock screen. There are
* two {@link Mode}s of operation, lock and unlock. This will show the appropriate
@@ -93,6 +100,12 @@
private boolean mShowLockBeforeUnlock = false;
+ // The following were added to support FaceLock
+ private IFaceLockInterface mFaceLockService;
+ private boolean mBoundToFaceLockService = false;
+ private boolean mFaceLockServiceRunning = false;
+ private View mFaceLockAreaView;
+
/**
* The current {@link KeyguardScreen} will use this to communicate back to us.
*/
@@ -180,7 +193,7 @@
private Runnable mRecreateRunnable = new Runnable() {
public void run() {
- updateScreen(mMode, false);
+ updateScreen(mMode, true);
}
};
@@ -400,7 +413,7 @@
// then finish and get out
if (mEnableFallback || mAccountIndex >= mAccounts.length) {
if (mUnlockScreen == null) {
- Log.w(TAG, "no unlock screen when trying to enable fallback");
+ if (DEBUG) Log.w(TAG, "no unlock screen when trying to enable fallback");
} else if (mUnlockScreen instanceof PatternUnlockScreen) {
((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback);
}
@@ -459,7 +472,7 @@
public void reset() {
mIsVerifyUnlockOnly = false;
mForgotPattern = false;
- updateScreen(getInitialMode(), false);
+ post(mRecreateRunnable);
}
@Override
@@ -485,9 +498,7 @@
private void recreateLockScreen() {
if (mLockScreen != null) {
- if (mLockScreen.getVisibility() == View.VISIBLE) {
- ((KeyguardScreen) mLockScreen).onPause();
- }
+ ((KeyguardScreen) mLockScreen).onPause();
((KeyguardScreen) mLockScreen).cleanUp();
removeView(mLockScreen);
}
@@ -499,9 +510,7 @@
private void recreateUnlockScreen(UnlockMode unlockMode) {
if (mUnlockScreen != null) {
- if (mUnlockScreen.getVisibility() == View.VISIBLE) {
- ((KeyguardScreen) mUnlockScreen).onPause();
- }
+ ((KeyguardScreen) mUnlockScreen).onPause();
((KeyguardScreen) mUnlockScreen).cleanUp();
removeView(mUnlockScreen);
}
@@ -584,6 +593,10 @@
}
private boolean isSecure() {
+ // TODO: make this work with SIM and Account cases below.
+ boolean usingBiometric = mLockPatternUtils.usingBiometricWeak();
+ if (usingBiometric && mLockPatternUtils.isBiometricEnabled())
+ return true;
UnlockMode unlockMode = getUnlockMode();
boolean secure = false;
switch (unlockMode) {
@@ -611,7 +624,7 @@
private void updateScreen(Mode mode, boolean force) {
if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode
- + " last mode=" + mMode, new RuntimeException());
+ + " last mode=" + mMode + ", force = " + force, new RuntimeException());
mMode = mode;
@@ -691,6 +704,12 @@
mKeyguardScreenCallback,
mUpdateMonitor.getFailedAttempts());
view.setEnableFallback(mEnableFallback);
+
+ // TODO(bcolonna): For pattern unlock, it can give us the view where the pattern is
+ // displayed and FaceLock can draw in that area.
+ // For other views it's not so simple and we should probably change how the FaceLock
+ // area is determined.
+ mFaceLockAreaView = view.getUnlockAreaView();
unlockView = view;
} else if (unlockMode == UnlockMode.SimPuk) {
unlockView = new SimPukUnlockScreen(
@@ -916,5 +935,142 @@
return mBitmap.getHeight();
}
}
-}
+ // Everything below pertains to FaceLock - might want to separate this out
+
+ // Binds to FaceLock service, but does not tell it to start
+ public void bindToFaceLock() {
+ if (mLockPatternUtils.usingBiometricWeak()) {
+ if (!mBoundToFaceLockService) {
+ if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
+ mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
+ mFaceLockConnection,
+ Context.BIND_AUTO_CREATE);
+ if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
+ mBoundToFaceLockService = true;
+ } else {
+ // On startup I've seen onScreenTurnedOn() get called twice without
+ // onScreenTurnedOff() being called in between, which can cause this (bcolonna)
+ if (DEBUG) Log.w(TAG, "Attempt to bind to FaceLock when already bound");
+ }
+ }
+ }
+
+ // Tells FaceLock to stop and then unbinds from the FaceLock service
+ public void stopAndUnbindFromFaceLock() {
+ if (mLockPatternUtils.usingBiometricWeak()) {
+ stopFaceLock();
+
+ if (mBoundToFaceLockService) {
+ if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
+ mContext.unbindService(mFaceLockConnection);
+ if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
+ mBoundToFaceLockService = false;
+ } else {
+ // This could probably happen after the session when someone activates FaceLock
+ // because it wasn't active when the phone was turned on
+ if (DEBUG) Log.w(TAG, "Attempt to unbind from FaceLock when not bound");
+ }
+ }
+ }
+
+ private ServiceConnection mFaceLockConnection = new ServiceConnection() {
+ // Completes connection, registers callback and starts FaceLock when service is bound
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder iservice) {
+ mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice);
+ if (DEBUG) Log.d(TAG, "Connected to FaceLock service");
+ try {
+ mFaceLockService.registerCallback(mFaceLockCallback);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Remote exception");
+ }
+
+ // TODO(bcolonna): Need to set location properly (only works for pattern view now)
+ if (mFaceLockAreaView != null) {
+ int[] unlockLocationOnScreen = new int[2];
+ mFaceLockAreaView.getLocationOnScreen(unlockLocationOnScreen);
+ int x = unlockLocationOnScreen[0];
+ int y = unlockLocationOnScreen[1];
+ int w = mFaceLockAreaView.getWidth();
+ int h = mFaceLockAreaView.getHeight();
+ if (DEBUG) Log.d(TAG, "(x,y) (wxh): (" + x + "," + y + ") (" + w + "x" + h + ")");
+ startFaceLock(mFaceLockAreaView.getWindowToken(), x, y, w, h);
+ }
+ }
+
+ // Cleans up if FaceLock service unexpectedly disconnects
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ mFaceLockService = null;
+ if (DEBUG) Log.w(TAG, "Unexpected disconnect from FaceLock service");
+ }
+ };
+
+ // Tells the FaceLock service to start displaying its UI and perform recognition
+ public void startFaceLock(IBinder windowToken, int x, int y, int h, int w)
+ {
+ if (mLockPatternUtils.usingBiometricWeak()) {
+ if (!mFaceLockServiceRunning) {
+ if (DEBUG) Log.d(TAG, "Starting FaceLock");
+ try {
+ mFaceLockService.startUi(windowToken, x, y, h, w);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Remote exception");
+ }
+ mFaceLockServiceRunning = true;
+ } else {
+ if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running");
+ }
+ }
+ }
+
+ // Tells the FaceLock service to stop displaying its UI and stop recognition
+ public void stopFaceLock()
+ {
+ if (mLockPatternUtils.usingBiometricWeak()) {
+ // Note that attempting to stop FaceLock when it's not running is not an issue.
+ // FaceLock can return, which stops it and then we try to stop it when the
+ // screen is turned off. That's why we check.
+ if (mFaceLockServiceRunning) {
+ try {
+ if (DEBUG) Log.d(TAG, "Stopping FaceLock");
+ mFaceLockService.stopUi();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Remote exception");
+ }
+ mFaceLockServiceRunning = false;
+ }
+ }
+ }
+
+ // Implements the FaceLock service callback interface defined in AIDL
+ private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() {
+
+ // Stops the FaceLock UI and indicates that the phone should be unlocked
+ @Override
+ public void unlock() {
+ if (DEBUG) Log.d(TAG, "FaceLock unlock");
+ stopFaceLock();
+ mKeyguardScreenCallback.keyguardDone(true);
+ mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
+ }
+
+ // Stops the FaceLock UI and exposes the backup method without unlocking
+ @Override
+ public void cancel() {
+ // In this case, either the user has cancelled out, or FaceLock failed to recognize them
+ if (DEBUG) Log.d(TAG, "FaceLock cancel");
+ stopFaceLock();
+ }
+
+ // Stops the FaceLock UI and puts the phone to sleep
+ @Override
+ public void sleepDevice() {
+ // In this case, it appears the phone has been turned on accidentally
+ if (DEBUG) Log.d(TAG, "FaceLock accidental turn on");
+ stopFaceLock();
+ // TODO(bcolonna): how do we put the phone back to sleep (i.e., turn off the screen)
+ }
+ };
+}
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index a3db1c3..0cafeb5a 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -199,7 +199,11 @@
setFocusableInTouchMode(true);
}
-
+ // TODO(bcolonna): This is to tell FaceLock where to draw...but this covers up the wireless
+ // service text, so we will want to change the way the area is specified
+ public View getUnlockAreaView() {
+ return mLockPatternView;
+ }
public void setEnableFallback(boolean state) {
if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b69a7c2..20088b1 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -384,7 +384,7 @@
st.menu.stopDispatchingItemsChanged();
if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
// Ditch the menu created above
- st.menu = null;
+ st.setMenu(null);
if (mActionBar != null) {
// Don't show it in the action bar either
@@ -1401,7 +1401,9 @@
if (event.getRepeatCount() > 0) break;
if (featureId < 0) break;
// Currently don't do anything with long press.
- dispatcher.startTracking(event, this);
+ if (dispatcher != null) {
+ dispatcher.startTracking(event, this);
+ }
return true;
}
@@ -3207,7 +3209,17 @@
}
void setMenu(MenuBuilder menu) {
+ if (menu == this.menu) return;
+
+ if (this.menu != null) {
+ this.menu.removeMenuPresenter(iconMenuPresenter);
+ this.menu.removeMenuPresenter(listMenuPresenter);
+ }
this.menu = menu;
+ if (menu != null) {
+ if (iconMenuPresenter != null) menu.addMenuPresenter(iconMenuPresenter);
+ if (listMenuPresenter != null) menu.addMenuPresenter(listMenuPresenter);
+ }
}
MenuView getListMenuView(MenuPresenter.Callback cb) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 304df72..86671bd 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -189,16 +189,16 @@
static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
static final int STATUS_BAR_LAYER = 15;
static final int STATUS_BAR_PANEL_LAYER = 16;
- // the navigation bar, if available, shows atop most things
- static final int NAVIGATION_BAR_LAYER = 17;
// the on-screen volume indicator and controller shown when the user
// changes the device volume
- static final int VOLUME_OVERLAY_LAYER = 18;
+ static final int VOLUME_OVERLAY_LAYER = 17;
+ // things in here CAN NOT take focus, but are shown on top of everything else.
+ static final int SYSTEM_OVERLAY_LAYER = 18;
+ // the navigation bar, if available, shows atop most things
+ static final int NAVIGATION_BAR_LAYER = 19;
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- static final int DRAG_LAYER = 19;
- // things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 20;
+ static final int DRAG_LAYER = 20;
static final int SECURE_SYSTEM_OVERLAY_LAYER = 21;
static final int BOOT_PROGRESS_LAYER = 22;
// the (mouse) pointer layer
@@ -894,10 +894,10 @@
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
- lp.flags =
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
lp.format = PixelFormat.TRANSLUCENT;
lp.setTitle("PointerLocation");
WindowManager wm = (WindowManager)
@@ -995,6 +995,7 @@
// These types of windows can't receive input events.
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
break;
}
}
@@ -1993,6 +1994,13 @@
"Laying out navigation bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
}
+ } else if (attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
+ && ((fl & FLAG_FULLSCREEN) != 0)) {
+ // Fullscreen secure system overlays get what they ask for.
+ pf.left = df.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = mUnrestrictedScreenTop;
+ pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
} else {
pf.left = df.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = cf.top = mRestrictedScreenTop;
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 8861bee..38968f9 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -103,6 +103,8 @@
TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17,
TYPE_POINTER = FIRST_SYSTEM_WINDOW+18,
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
+ TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
+ TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 997318a..be2ef82 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -163,6 +163,10 @@
private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
private static final int MSG_RUN_FULL_RESTORE = 10;
+ // backup task state machine tick
+ static final int MSG_BACKUP_RESTORE_STEP = 20;
+ static final int MSG_OP_COMPLETE = 21;
+
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -344,7 +348,16 @@
static final int OP_ACKNOWLEDGED = 1;
static final int OP_TIMEOUT = -1;
- final SparseIntArray mCurrentOperations = new SparseIntArray();
+ class Operation {
+ public int state;
+ public BackupRestoreTask callback;
+
+ Operation(int initialState, BackupRestoreTask callbackObj) {
+ state = initialState;
+ callback = callbackObj;
+ }
+ }
+ final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
final Object mCurrentOpLock = new Object();
final Random mTokenGenerator = new Random();
@@ -442,13 +455,16 @@
}
}
+ // At this point, we have started a new journal file, and the old
+ // file identity is being passed to the backup processing task.
+ // When it completes successfully, that old journal file will be
+ // deleted. If we crash prior to that, the old journal is parsed
+ // at next boot and the journaled requests fulfilled.
if (queue.size() > 0) {
- // At this point, we have started a new journal file, and the old
- // file identity is being passed to the backup processing thread.
- // When it completes successfully, that old journal file will be
- // deleted. If we crash prior to that, the old journal is parsed
- // at next boot and the journaled requests fulfilled.
- (new PerformBackupTask(transport, queue, oldJournal)).run();
+ // Spin up a backup state sequence and set it running
+ PerformBackupTask pbt = new PerformBackupTask(transport, queue, oldJournal);
+ Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
+ sendMessage(pbtMessage);
} else {
Slog.v(TAG, "Backup requested but nothing pending");
mWakelock.release();
@@ -456,6 +472,29 @@
break;
}
+ case MSG_BACKUP_RESTORE_STEP:
+ {
+ try {
+ BackupRestoreTask task = (BackupRestoreTask) msg.obj;
+ if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
+ task.execute();
+ } catch (ClassCastException e) {
+ Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
+ }
+ break;
+ }
+
+ case MSG_OP_COMPLETE:
+ {
+ try {
+ BackupRestoreTask task = (BackupRestoreTask) msg.obj;
+ task.operationComplete();
+ } catch (ClassCastException e) {
+ Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
+ }
+ break;
+ }
+
case MSG_RUN_FULL_BACKUP:
{
FullBackupParams params = (FullBackupParams)msg.obj;
@@ -469,9 +508,12 @@
{
RestoreParams params = (RestoreParams)msg.obj;
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
- (new PerformRestoreTask(params.transport, params.observer,
+ PerformRestoreTask task = new PerformRestoreTask(
+ params.transport, params.observer,
params.token, params.pkgInfo, params.pmToken,
- params.needFullBackup, params.filterSet)).run();
+ params.needFullBackup, params.filterSet);
+ Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
+ sendMessage(restoreMsg);
break;
}
@@ -540,15 +582,7 @@
case MSG_TIMEOUT:
{
- synchronized (mCurrentOpLock) {
- final int token = msg.arg1;
- int state = mCurrentOperations.get(token, OP_TIMEOUT);
- if (state == OP_PENDING) {
- if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + token);
- mCurrentOperations.put(token, OP_TIMEOUT);
- }
- mCurrentOpLock.notifyAll();
- }
+ handleTimeout(msg.arg1, msg.obj);
break;
}
@@ -558,7 +592,7 @@
if (mActiveRestoreSession != null) {
// Client app left the restore session dangling. We know that it
// can't be in the middle of an actual restore operation because
- // those are executed serially on this same handler thread. Clean
+ // the timeout is suspended while a restore is in progress. Clean
// up now.
Slog.w(TAG, "Restore session timed out; aborting");
post(mActiveRestoreSession.new EndRestoreRunnable(
@@ -1113,12 +1147,14 @@
}
// Enqueue a new backup of every participant
- int N = mBackupParticipants.size();
- for (int i=0; i<N; i++) {
- int uid = mBackupParticipants.keyAt(i);
- HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
- for (ApplicationInfo app: participants) {
- dataChangedImpl(app.packageName);
+ synchronized (mBackupParticipants) {
+ int N = mBackupParticipants.size();
+ for (int i=0; i<N; i++) {
+ int uid = mBackupParticipants.keyAt(i);
+ HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
+ for (ApplicationInfo app: participants) {
+ dataChangedImpl(app.packageName);
+ }
}
}
}
@@ -1588,50 +1624,120 @@
}
// -----
- // Utility methods used by the asynchronous-with-timeout backup/restore operations
- boolean waitUntilOperationComplete(int token) {
- int finalState = OP_PENDING;
+ // Interface and methods used by the asynchronous-with-timeout backup/restore operations
+
+ interface BackupRestoreTask {
+ // Execute one tick of whatever state machine the task implements
+ void execute();
+
+ // An operation that wanted a callback has completed
+ void operationComplete();
+
+ // An operation that wanted a callback has timed out
+ void handleTimeout();
+ }
+
+ void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback) {
+ if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
+ + " interval=" + interval);
synchronized (mCurrentOpLock) {
- try {
- while ((finalState = mCurrentOperations.get(token, OP_TIMEOUT)) == OP_PENDING) {
- try {
- mCurrentOpLock.wait();
- } catch (InterruptedException e) {}
+ mCurrentOperations.put(token, new Operation(OP_PENDING, callback));
+
+ Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0, callback);
+ mBackupHandler.sendMessageDelayed(msg, interval);
+ }
+ }
+
+ // synchronous waiter case
+ boolean waitUntilOperationComplete(int token) {
+ if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
+ + Integer.toHexString(token));
+ int finalState = OP_PENDING;
+ Operation op = null;
+ synchronized (mCurrentOpLock) {
+ while (true) {
+ op = mCurrentOperations.get(token);
+ if (op == null) {
+ // mysterious disappearance: treat as success with no callback
+ break;
+ } else {
+ if (op.state == OP_PENDING) {
+ try {
+ mCurrentOpLock.wait();
+ } catch (InterruptedException e) {}
+ // When the wait is notified we loop around and recheck the current state
+ } else {
+ // No longer pending; we're done
+ finalState = op.state;
+ break;
+ }
}
- } catch (IndexOutOfBoundsException e) {
- // the operation has been mysteriously cleared from our
- // bookkeeping -- consider this a success and ignore it.
}
}
+
mBackupHandler.removeMessages(MSG_TIMEOUT);
if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
+ " complete: finalState=" + finalState);
return finalState == OP_ACKNOWLEDGED;
}
- void prepareOperationTimeout(int token, long interval) {
- if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
- + " interval=" + interval);
+ void handleTimeout(int token, Object obj) {
+ // Notify any synchronous waiters
+ Operation op = null;
synchronized (mCurrentOpLock) {
- mCurrentOperations.put(token, OP_PENDING);
- Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0);
- mBackupHandler.sendMessageDelayed(msg, interval);
+ op = mCurrentOperations.get(token);
+ if (MORE_DEBUG) {
+ if (op == null) Slog.w(TAG, "Timeout of token " + Integer.toHexString(token)
+ + " but no op found");
+ }
+ int state = (op != null) ? op.state : OP_TIMEOUT;
+ if (state == OP_PENDING) {
+ if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + Integer.toHexString(token));
+ op.state = OP_TIMEOUT;
+ mCurrentOperations.put(token, op);
+ }
+ mCurrentOpLock.notifyAll();
+ }
+
+ // If there's a TimeoutHandler for this event, call it
+ if (op != null && op.callback != null) {
+ op.callback.handleTimeout();
}
}
// ----- Back up a set of applications via a worker thread -----
- class PerformBackupTask implements Runnable {
- private static final String TAG = "PerformBackupThread";
+ enum BackupState {
+ INITIAL,
+ RUNNING_QUEUE,
+ FINAL
+ }
+
+ class PerformBackupTask implements BackupRestoreTask {
+ private static final String TAG = "PerformBackupTask";
+
IBackupTransport mTransport;
ArrayList<BackupRequest> mQueue;
+ ArrayList<BackupRequest> mOriginalQueue;
File mStateDir;
File mJournal;
+ BackupState mCurrentState;
+
+ // carried information about the current in-flight operation
+ PackageInfo mCurrentPackage;
+ File mSavedStateName;
+ File mBackupDataName;
+ File mNewStateName;
+ ParcelFileDescriptor mSavedState;
+ ParcelFileDescriptor mBackupData;
+ ParcelFileDescriptor mNewState;
+ int mStatus;
+ boolean mFinished;
public PerformBackupTask(IBackupTransport transport, ArrayList<BackupRequest> queue,
File journal) {
mTransport = transport;
- mQueue = queue;
+ mOriginalQueue = queue;
mJournal = journal;
try {
@@ -1639,26 +1745,62 @@
} catch (RemoteException e) {
// can't happen; the transport is local
}
+
+ mCurrentState = BackupState.INITIAL;
+ mFinished = false;
}
- public void run() {
- int status = BackupConstants.TRANSPORT_OK;
- long startRealtime = SystemClock.elapsedRealtime();
+ // Main entry point: perform one chunk of work, updating the state as appropriate
+ // and reposting the next chunk to the primary backup handler thread.
+ @Override
+ public void execute() {
+ switch (mCurrentState) {
+ case INITIAL:
+ beginBackup();
+ break;
+
+ case RUNNING_QUEUE:
+ invokeNextAgent();
+ break;
+
+ case FINAL:
+ if (!mFinished) finalizeBackup();
+ else {
+ Slog.e(TAG, "Duplicate finish");
+ }
+ mFinished = true;
+ break;
+ }
+ }
+
+ // We're starting a backup pass. Initialize the transport and send
+ // the PM metadata blob if we haven't already.
+ void beginBackup() {
+ mStatus = BackupConstants.TRANSPORT_OK;
+
+ // Sanity check: if the queue is empty we have no work to do.
+ if (mOriginalQueue.isEmpty()) {
+ Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
+ return;
+ }
+
+ // We need to retain the original queue contents in case of transport
+ // failure, but we want a working copy that we can manipulate along
+ // the way.
+ mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
+
if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
- // Backups run at background priority
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
+ File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
try {
EventLog.writeEvent(EventLogTags.BACKUP_START, mTransport.transportDirName());
// If we haven't stored package manager metadata yet, we must init the transport.
- File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
- if (status == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
+ if (mStatus == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
resetBackupState(mStateDir); // Just to make sure.
- status = mTransport.initializeDevice();
- if (status == BackupConstants.TRANSPORT_OK) {
+ mStatus = mTransport.initializeDevice();
+ if (mStatus == BackupConstants.TRANSPORT_OK) {
EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
} else {
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
@@ -1671,207 +1813,219 @@
// directly and use a synthetic BackupRequest. We always run this pass
// because it's cheap and this way we guarantee that we don't get out of
// step even if we're selecting among various transports at run time.
- if (status == BackupConstants.TRANSPORT_OK) {
+ if (mStatus == BackupConstants.TRANSPORT_OK) {
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
mPackageManager, allAgentPackages());
- status = processOneBackup(PACKAGE_MANAGER_SENTINEL,
+ mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
}
- if (status == BackupConstants.TRANSPORT_OK) {
- // Now run all the backups in our queue
- status = doQueuedBackups(mTransport);
- }
-
- if (status == BackupConstants.TRANSPORT_OK) {
- // Tell the transport to finish everything it has buffered
- status = mTransport.finishBackup();
- if (status == BackupConstants.TRANSPORT_OK) {
- int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, mQueue.size(), millis);
- } else {
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(finish)");
- Slog.e(TAG, "Transport error in finishBackup()");
- }
- }
-
- if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
- // The backend reports that our dataset has been wiped. We need to
- // reset all of our bookkeeping and instead run a new backup pass for
- // everything.
+ if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
+ // The backend reports that our dataset has been wiped. Note this in
+ // the event log; the no-success code below will reset the backup
+ // state as well.
EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
- resetBackupState(mStateDir);
}
} catch (Exception e) {
Slog.e(TAG, "Error in backup thread", e);
- status = BackupConstants.TRANSPORT_ERROR;
+ mStatus = BackupConstants.TRANSPORT_ERROR;
} finally {
- // If everything actually went through and this is the first time we've
- // done a backup, we can now record what the current backup dataset token
- // is.
- if ((mCurrentToken == 0) && (status == BackupConstants.TRANSPORT_OK)) {
- try {
- mCurrentToken = mTransport.getCurrentRestoreSet();
- } catch (RemoteException e) { /* cannot happen */ }
- writeRestoreTokens();
+ // If we've succeeded so far, invokeAgentForBackup() will have run the PM
+ // metadata and its completion/timeout callback will continue the state
+ // machine chain. If it failed that won't happen; we handle that now.
+ if (mStatus != BackupConstants.TRANSPORT_OK) {
+ // if things went wrong at this point, we need to
+ // restage everything and try again later.
+ resetBackupState(mStateDir); // Just to make sure.
+ executeNextState(BackupState.FINAL);
}
-
- // If things went wrong, we need to re-stage the apps we had expected
- // to be backing up in this pass. This journals the package names in
- // the current active pending-backup file, not in the we are holding
- // here in mJournal.
- if (status != BackupConstants.TRANSPORT_OK) {
- Slog.w(TAG, "Backup pass unsuccessful, restaging");
- for (BackupRequest req : mQueue) {
- dataChangedImpl(req.packageName);
- }
-
- // We also want to reset the backup schedule based on whatever
- // the transport suggests by way of retry/backoff time.
- try {
- startBackupAlarmsLocked(mTransport.requestBackupTime());
- } catch (RemoteException e) { /* cannot happen */ }
- }
-
- // Either backup was successful, in which case we of course do not need
- // this pass's journal any more; or it failed, in which case we just
- // re-enqueued all of these packages in the current active journal.
- // Either way, we no longer need this pass's journal.
- if (mJournal != null && !mJournal.delete()) {
- Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
- }
-
- // Only once we're entirely finished do we release the wakelock
- if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
- backupNow();
- }
-
- mWakelock.release();
}
}
- private int doQueuedBackups(IBackupTransport transport) {
- for (BackupRequest request : mQueue) {
- Slog.d(TAG, "starting agent for backup of " + request);
+ // Transport has been initialized and the PM metadata submitted successfully
+ // if that was warranted. Now we process the single next thing in the queue.
+ void invokeNextAgent() {
+ mStatus = BackupConstants.TRANSPORT_OK;
- // Verify that the requested app exists; it might be something that
- // requested a backup but was then uninstalled. The request was
- // journalled and rather than tamper with the journal it's safer
- // to sanity-check here. This also gives us the classname of the
- // package's backup agent.
- PackageInfo pkg;
- try {
- pkg = mPackageManager.getPackageInfo(request.packageName, 0);
- } catch (NameNotFoundException e) {
- Slog.d(TAG, "Package does not exist; skipping");
- continue;
- }
+ // Sanity check that we have work to do. If not, skip to the end where
+ // we reestablish the wakelock invariants etc.
+ if (mQueue.isEmpty()) {
+ Slog.e(TAG, "Running queue but it's empty!");
+ executeNextState(BackupState.FINAL);
+ return;
+ }
+
+ // pop the entry we're going to process on this step
+ BackupRequest request = mQueue.get(0);
+ mQueue.remove(0);
+
+ Slog.d(TAG, "starting agent for backup of " + request);
+
+ // Verify that the requested app exists; it might be something that
+ // requested a backup but was then uninstalled. The request was
+ // journalled and rather than tamper with the journal it's safer
+ // to sanity-check here. This also gives us the classname of the
+ // package's backup agent.
+ try {
+ mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
+ PackageManager.GET_SIGNATURES);
IBackupAgent agent = null;
try {
- mWakelock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
- agent = bindToAgentSynchronous(pkg.applicationInfo,
+ mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
+ agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
IApplicationThread.BACKUP_MODE_INCREMENTAL);
if (agent != null) {
- int result = processOneBackup(request.packageName, agent, transport);
- if (result != BackupConstants.TRANSPORT_OK) return result;
+ mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
+ // at this point we'll either get a completion callback from the
+ // agent, or a timeout message on the main handler. either way, we're
+ // done here as long as we're successful so far.
+ } else {
+ // Timeout waiting for the agent
+ mStatus = BackupConstants.AGENT_ERROR;
}
} catch (SecurityException ex) {
// Try for the next one.
Slog.d(TAG, "error in bind/backup", ex);
- } finally {
- try { // unbind even on timeout, just in case
- mActivityManager.unbindBackupAgent(pkg.applicationInfo);
- } catch (RemoteException e) {}
+ mStatus = BackupConstants.AGENT_ERROR;
+ }
+ } catch (NameNotFoundException e) {
+ Slog.d(TAG, "Package does not exist; skipping");
+ } finally {
+ mWakelock.setWorkSource(null);
+
+ // If there was an agent error, no timeout/completion handling will occur.
+ // That means we need to deal with the next state ourselves.
+ if (mStatus != BackupConstants.TRANSPORT_OK) {
+ BackupState nextState = BackupState.RUNNING_QUEUE;
+
+ // An agent-level failure means we reenqueue this one agent for
+ // a later retry, but otherwise proceed normally.
+ if (mStatus == BackupConstants.AGENT_ERROR) {
+ if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName
+ + " - restaging");
+ dataChangedImpl(request.packageName);
+ mStatus = BackupConstants.TRANSPORT_OK;
+ if (mQueue.isEmpty()) nextState = BackupState.FINAL;
+ } else if (mStatus != BackupConstants.TRANSPORT_OK) {
+ // Transport-level failure means we reenqueue everything
+ revertAndEndBackup();
+ nextState = BackupState.FINAL;
+ }
+
+ executeNextState(nextState);
}
}
-
- mWakelock.setWorkSource(null);
-
- return BackupConstants.TRANSPORT_OK;
}
- private int processOneBackup(String packageName, IBackupAgent agent,
+ void finalizeBackup() {
+ // Either backup was successful, in which case we of course do not need
+ // this pass's journal any more; or it failed, in which case we just
+ // re-enqueued all of these packages in the current active journal.
+ // Either way, we no longer need this pass's journal.
+ if (mJournal != null && !mJournal.delete()) {
+ Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
+ }
+
+ // If everything actually went through and this is the first time we've
+ // done a backup, we can now record what the current backup dataset token
+ // is.
+ if ((mCurrentToken == 0) && (mStatus == BackupConstants.TRANSPORT_OK)) {
+ try {
+ mCurrentToken = mTransport.getCurrentRestoreSet();
+ } catch (RemoteException e) {} // can't happen
+ writeRestoreTokens();
+ }
+
+ // Set up the next backup pass
+ if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
+ backupNow();
+ }
+
+ // Only once we're entirely finished do we release the wakelock
+ Slog.i(TAG, "Backup pass finished.");
+ mWakelock.release();
+ }
+
+ // Invoke an agent's doBackup() and start a timeout message spinning on the main
+ // handler in case it doesn't get back to us.
+ int invokeAgentForBackup(String packageName, IBackupAgent agent,
IBackupTransport transport) {
if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName);
- File savedStateName = new File(mStateDir, packageName);
- File backupDataName = new File(mDataDir, packageName + ".data");
- File newStateName = new File(mStateDir, packageName + ".new");
+ mSavedStateName = new File(mStateDir, packageName);
+ mBackupDataName = new File(mDataDir, packageName + ".data");
+ mNewStateName = new File(mStateDir, packageName + ".new");
- ParcelFileDescriptor savedState = null;
- ParcelFileDescriptor backupData = null;
- ParcelFileDescriptor newState = null;
+ mSavedState = null;
+ mBackupData = null;
+ mNewState = null;
- PackageInfo packInfo;
final int token = generateToken();
try {
// Look up the package info & signatures. This is first so that if it
// throws an exception, there's no file setup yet that would need to
// be unraveled.
if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
- // The metadata 'package' is synthetic
- packInfo = new PackageInfo();
- packInfo.packageName = packageName;
- } else {
- packInfo = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES);
+ // The metadata 'package' is synthetic; construct one and make
+ // sure our global state is pointed at it
+ mCurrentPackage = new PackageInfo();
+ mCurrentPackage.packageName = packageName;
}
// In a full backup, we pass a null ParcelFileDescriptor as
// the saved-state "file". This is by definition an incremental,
// so we build a saved state file to pass.
- savedState = ParcelFileDescriptor.open(savedStateName,
+ mSavedState = ParcelFileDescriptor.open(mSavedStateName,
ParcelFileDescriptor.MODE_READ_ONLY |
ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
- backupData = ParcelFileDescriptor.open(backupDataName,
+ mBackupData = ParcelFileDescriptor.open(mBackupDataName,
ParcelFileDescriptor.MODE_READ_WRITE |
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
- newState = ParcelFileDescriptor.open(newStateName,
+ mNewState = ParcelFileDescriptor.open(mNewStateName,
ParcelFileDescriptor.MODE_READ_WRITE |
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
// Initiate the target's backup pass
- prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
- agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
- boolean success = waitUntilOperationComplete(token);
-
- if (!success) {
- // timeout -- bail out into the failed-transaction logic
- throw new RuntimeException("Backup timeout");
- }
-
- logBackupComplete(packageName);
- if (DEBUG) Slog.v(TAG, "doBackup() success");
+ prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, this);
+ agent.doBackup(mSavedState, mBackupData, mNewState, token, mBackupManagerBinder);
} catch (Exception e) {
- Slog.e(TAG, "Error backing up " + packageName, e);
- EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString());
- backupDataName.delete();
- newStateName.delete();
- return BackupConstants.TRANSPORT_ERROR;
- } finally {
- try { if (savedState != null) savedState.close(); } catch (IOException e) {}
- try { if (backupData != null) backupData.close(); } catch (IOException e) {}
- try { if (newState != null) newState.close(); } catch (IOException e) {}
- savedState = backupData = newState = null;
- synchronized (mCurrentOpLock) {
- mCurrentOperations.clear();
- }
+ Slog.e(TAG, "Error invoking for backup on " + packageName);
+ EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
+ e.toString());
+ agentErrorCleanup();
+ return BackupConstants.AGENT_ERROR;
}
- // Now propagate the newly-backed-up data to the transport
- int result = BackupConstants.TRANSPORT_OK;
+ // At this point the agent is off and running. The next thing to happen will
+ // either be a callback from the agent, at which point we'll process its data
+ // for transport, or a timeout. Either way the next phase will happen in
+ // response to the TimeoutHandler interface callbacks.
+ return BackupConstants.TRANSPORT_OK;
+ }
+
+ @Override
+ public void operationComplete() {
+ // Okay, the agent successfully reported back to us. Spin the data off to the
+ // transport and proceed with the next stage.
+ if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
+ + mCurrentPackage.packageName);
+ mBackupHandler.removeMessages(MSG_TIMEOUT);
+ clearAgentState();
+
+ ParcelFileDescriptor backupData = null;
+ mStatus = BackupConstants.TRANSPORT_OK;
try {
- int size = (int) backupDataName.length();
+ int size = (int) mBackupDataName.length();
if (size > 0) {
- if (result == BackupConstants.TRANSPORT_OK) {
- backupData = ParcelFileDescriptor.open(backupDataName,
+ if (mStatus == BackupConstants.TRANSPORT_OK) {
+ backupData = ParcelFileDescriptor.open(mBackupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- result = transport.performBackup(packInfo, backupData);
+ mStatus = mTransport.performBackup(mCurrentPackage, backupData);
}
// TODO - We call finishBackup() for each application backed up, because
@@ -1879,8 +2033,8 @@
// hold off on finishBackup() until the end, which implies holding off on
// renaming *all* the output state files (see below) until that happens.
- if (result == BackupConstants.TRANSPORT_OK) {
- result = transport.finishBackup();
+ if (mStatus == BackupConstants.TRANSPORT_OK) {
+ mStatus = mTransport.finishBackup();
}
} else {
if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
@@ -1889,22 +2043,102 @@
// After successful transport, delete the now-stale data
// and juggle the files so that next time we supply the agent
// with the new state file it just created.
- if (result == BackupConstants.TRANSPORT_OK) {
- backupDataName.delete();
- newStateName.renameTo(savedStateName);
- EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, packageName, size);
+ if (mStatus == BackupConstants.TRANSPORT_OK) {
+ mBackupDataName.delete();
+ mNewStateName.renameTo(mSavedStateName);
+ EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE,
+ mCurrentPackage.packageName, size);
+ logBackupComplete(mCurrentPackage.packageName);
} else {
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE,
+ mCurrentPackage.packageName);
}
} catch (Exception e) {
- Slog.e(TAG, "Transport error backing up " + packageName, e);
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
- result = BackupConstants.TRANSPORT_ERROR;
+ Slog.e(TAG, "Transport error backing up " + mCurrentPackage.packageName, e);
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE,
+ mCurrentPackage.packageName);
+ mStatus = BackupConstants.TRANSPORT_ERROR;
} finally {
try { if (backupData != null) backupData.close(); } catch (IOException e) {}
}
- return result;
+ // If we encountered an error here it's a transport-level failure. That
+ // means we need to halt everything and reschedule everything for next time.
+ final BackupState nextState;
+ if (mStatus != BackupConstants.TRANSPORT_OK) {
+ revertAndEndBackup();
+ nextState = BackupState.FINAL;
+ } else {
+ // Success! Proceed with the next app if any, otherwise we're done.
+ nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
+ }
+
+ executeNextState(nextState);
+ }
+
+ @Override
+ public void handleTimeout() {
+ // Whoops, the current agent timed out running doBackup(). Tidy up and restage
+ // it for the next time we run a backup pass.
+ // !!! TODO: keep track of failure counts per agent, and blacklist those which
+ // fail repeatedly (i.e. have proved themselves to be buggy).
+ Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
+ EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
+ "timeout");
+ agentErrorCleanup();
+ dataChangedImpl(mCurrentPackage.packageName);
+ }
+
+ void revertAndEndBackup() {
+ if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
+ for (BackupRequest request : mOriginalQueue) {
+ dataChangedImpl(request.packageName);
+ }
+ // We also want to reset the backup schedule based on whatever
+ // the transport suggests by way of retry/backoff time.
+ restartBackupAlarm();
+ }
+
+ void agentErrorCleanup() {
+ mBackupDataName.delete();
+ mNewStateName.delete();
+ clearAgentState();
+
+ executeNextState(mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
+ }
+
+ // Cleanup common to both success and failure cases
+ void clearAgentState() {
+ try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
+ try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
+ try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
+ mSavedState = mBackupData = mNewState = null;
+ synchronized (mCurrentOpLock) {
+ mCurrentOperations.clear();
+ }
+
+ // If this was a pseudopackage there's no associated Activity Manager state
+ if (mCurrentPackage.applicationInfo != null) {
+ try { // unbind even on timeout, just in case
+ mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
+ } catch (RemoteException e) {}
+ }
+ }
+
+ void restartBackupAlarm() {
+ synchronized (mQueueLock) {
+ try {
+ startBackupAlarmsLocked(mTransport.requestBackupTime());
+ } catch (RemoteException e) { /* cannot happen */ }
+ }
+ }
+
+ void executeNextState(BackupState nextState) {
+ if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
+ + this + " nextState=" + nextState);
+ mCurrentState = nextState;
+ Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
+ mBackupHandler.sendMessage(msg);
}
}
@@ -1959,7 +2193,7 @@
}
if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
- prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL);
+ prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, null);
mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
} catch (IOException e) {
Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
@@ -2320,7 +2554,7 @@
sendOnBackupPackage("Shared storage");
final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL);
+ prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL, null);
agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on shared storage");
@@ -2899,8 +3133,7 @@
try {
if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
+ info.path);
- prepareOperationTimeout(token,
- TIMEOUT_FULL_BACKUP_INTERVAL);
+ prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
// fire up the app's agent listening on the socket. If
// the agent is running in the system process we can't
// just invoke it asynchronously, so we provide a thread
@@ -3693,7 +3926,15 @@
return true;
}
- class PerformRestoreTask implements Runnable {
+ enum RestoreState {
+ INITIAL,
+ DOWNLOAD_DATA,
+ PM_METADATA,
+ RUNNING_QUEUE,
+ FINAL
+ }
+
+ class PerformRestoreTask implements BackupRestoreTask {
private IBackupTransport mTransport;
private IRestoreObserver mObserver;
private long mToken;
@@ -3702,6 +3943,21 @@
private int mPmToken;
private boolean mNeedFullBackup;
private HashSet<String> mFilterSet;
+ private long mStartRealtime;
+ private PackageManagerBackupAgent mPmAgent;
+ private List<PackageInfo> mAgentPackages;
+ private ArrayList<PackageInfo> mRestorePackages;
+ private RestoreState mCurrentState;
+ private int mCount;
+ private boolean mFinished;
+ private int mStatus;
+ private File mBackupDataName;
+ private File mNewStateName;
+ private File mSavedStateName;
+ private ParcelFileDescriptor mBackupData;
+ private ParcelFileDescriptor mNewState;
+ private PackageInfo mCurrentPackage;
+
class RestoreRequest {
public PackageInfo app;
@@ -3716,6 +3972,10 @@
PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
long restoreSetToken, PackageInfo targetPackage, int pmToken,
boolean needFullBackup, String[] filterSet) {
+ mCurrentState = RestoreState.INITIAL;
+ mFinished = false;
+ mPmAgent = null;
+
mTransport = transport;
mObserver = observer;
mToken = restoreSetToken;
@@ -3739,50 +3999,79 @@
}
}
- public void run() {
- long startRealtime = SystemClock.elapsedRealtime();
- if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
- + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
- + " mTargetPackage=" + mTargetPackage + " mFilterSet=" + mFilterSet
- + " mPmToken=" + mPmToken);
+ // Execute one tick of whatever state machine the task implements
+ @Override
+ public void execute() {
+ if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step: " + mCurrentState);
+ switch (mCurrentState) {
+ case INITIAL:
+ beginRestore();
+ break;
- PackageManagerBackupAgent pmAgent = null;
- int error = -1; // assume error
+ case DOWNLOAD_DATA:
+ downloadRestoreData();
+ break;
- // build the set of apps to restore
+ case PM_METADATA:
+ restorePmMetadata();
+ break;
+
+ case RUNNING_QUEUE:
+ restoreNextAgent();
+ break;
+
+ case FINAL:
+ if (!mFinished) finalizeRestore();
+ else {
+ Slog.e(TAG, "Duplicate finish");
+ }
+ mFinished = true;
+ break;
+ }
+ }
+
+ // Initialize and set up for the PM metadata restore, which comes first
+ void beginRestore() {
+ // Don't account time doing the restore as inactivity of the app
+ // that has opened a restore session.
+ mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
+
+ // Assume error until we successfully init everything
+ mStatus = BackupConstants.TRANSPORT_ERROR;
+
try {
// TODO: Log this before getAvailableRestoreSets, somehow
EventLog.writeEvent(EventLogTags.RESTORE_START, mTransport.transportDirName(), mToken);
// Get the list of all packages which have backup enabled.
// (Include the Package Manager metadata pseudo-package first.)
- ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
+ mRestorePackages = new ArrayList<PackageInfo>();
PackageInfo omPackage = new PackageInfo();
omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
- restorePackages.add(omPackage);
+ mRestorePackages.add(omPackage);
- List<PackageInfo> agentPackages = allAgentPackages();
+ mAgentPackages = 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);
+ for (int i = mAgentPackages.size() - 1; i >= 0; i--) {
+ final PackageInfo pkg = mAgentPackages.get(i);
if (! mFilterSet.contains(pkg.packageName)) {
- agentPackages.remove(i);
+ mAgentPackages.remove(i);
}
}
- if (DEBUG) {
+ if (MORE_DEBUG) {
Slog.i(TAG, "Post-filter package set for restore:");
- for (PackageInfo p : agentPackages) {
+ for (PackageInfo p : mAgentPackages) {
Slog.i(TAG, " " + p);
}
}
}
- restorePackages.addAll(agentPackages);
+ mRestorePackages.addAll(mAgentPackages);
} else {
// Just one package to attempt restore of
- restorePackages.add(mTargetPackage);
+ mRestorePackages.add(mTargetPackage);
}
// let the observer know that we're running
@@ -3790,306 +4079,412 @@
try {
// !!! TODO: get an actual count from the transport after
// its startRestore() runs?
- mObserver.restoreStarting(restorePackages.size());
+ mObserver.restoreStarting(mRestorePackages.size());
} catch (RemoteException e) {
Slog.d(TAG, "Restore observer died at restoreStarting");
mObserver = null;
}
}
+ } catch (RemoteException e) {
+ // Something has gone catastrophically wrong with the transport
+ Slog.e(TAG, "Error communicating with transport for restore");
+ executeNextState(RestoreState.FINAL);
+ return;
+ }
- if (mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0])) !=
- BackupConstants.TRANSPORT_OK) {
+ mStatus = BackupConstants.TRANSPORT_OK;
+ executeNextState(RestoreState.DOWNLOAD_DATA);
+ }
+
+ void downloadRestoreData() {
+ // Note that the download phase can be very time consuming, but we're executing
+ // it inline here on the looper. This is "okay" because it is not calling out to
+ // third party code; the transport is "trusted," and so we assume it is being a
+ // good citizen and timing out etc when appropriate.
+ //
+ // TODO: when appropriate, move the download off the looper and rearrange the
+ // error handling around that.
+ try {
+ mStatus = mTransport.startRestore(mToken,
+ mRestorePackages.toArray(new PackageInfo[0]));
+ if (mStatus != BackupConstants.TRANSPORT_OK) {
Slog.e(TAG, "Error starting restore operation");
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
+ executeNextState(RestoreState.FINAL);
return;
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error communicating with transport for restore");
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
+ mStatus = BackupConstants.TRANSPORT_ERROR;
+ executeNextState(RestoreState.FINAL);
+ return;
+ }
+ // Successful download of the data to be parceled out to the apps, so off we go.
+ executeNextState(RestoreState.PM_METADATA);
+ }
+
+ void restorePmMetadata() {
+ try {
String packageName = mTransport.nextRestorePackage();
if (packageName == null) {
Slog.e(TAG, "Error getting first restore package");
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
+ mStatus = BackupConstants.TRANSPORT_ERROR;
+ executeNextState(RestoreState.FINAL);
return;
} else if (packageName.equals("")) {
Slog.i(TAG, "No restore data available");
- int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, 0, millis);
+ mStatus = BackupConstants.TRANSPORT_OK;
+ executeNextState(RestoreState.FINAL);
return;
} else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
Slog.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
- + "\", found only \"" + packageName + "\"");
+ + "\", found only \"" + packageName + "\"");
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
"Package manager data missing");
+ executeNextState(RestoreState.FINAL);
return;
}
// Pull the Package Manager metadata from the restore set first
- pmAgent = new PackageManagerBackupAgent(
- mPackageManager, agentPackages);
- processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()),
+ PackageInfo omPackage = new PackageInfo();
+ omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
+ mPmAgent = new PackageManagerBackupAgent(
+ mPackageManager, mAgentPackages);
+ initiateOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(mPmAgent.onBind()),
mNeedFullBackup);
+ // The PM agent called operationComplete() already, because our invocation
+ // of it is process-local and therefore synchronous. That means that a
+ // RUNNING_QUEUE message is already enqueued. Only if we're unable to
+ // proceed with running the queue do we remove that pending message and
+ // jump straight to the FINAL state.
// Verify that the backup set includes metadata. If not, we can't do
// signature/version verification etc, so we simply do not proceed with
// the restore operation.
- if (!pmAgent.hasMetadata()) {
+ if (!mPmAgent.hasMetadata()) {
Slog.e(TAG, "No restore metadata available, so not restoring settings");
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
- "Package manager restore metadata missing");
+ "Package manager restore metadata missing");
+ mStatus = BackupConstants.TRANSPORT_ERROR;
+ mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
+ executeNextState(RestoreState.FINAL);
return;
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error communicating with transport for restore");
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
+ mStatus = BackupConstants.TRANSPORT_ERROR;
+ mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
+ executeNextState(RestoreState.FINAL);
+ return;
+ }
- int count = 0;
- for (;;) {
- packageName = mTransport.nextRestorePackage();
+ // Metadata is intact, so we can now run the restore queue. If we get here,
+ // we have already enqueued the necessary next-step message on the looper.
+ }
- if (packageName == null) {
- Slog.e(TAG, "Error getting next restore package");
- EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- return;
- } else if (packageName.equals("")) {
- if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
- break;
- }
+ void restoreNextAgent() {
+ try {
+ String packageName = mTransport.nextRestorePackage();
- if (mObserver != null) {
- try {
- mObserver.onUpdate(count, packageName);
- } catch (RemoteException e) {
- Slog.d(TAG, "Restore observer died in onUpdate");
- mObserver = null;
- }
- }
-
- Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
- if (metaInfo == null) {
- Slog.e(TAG, "Missing metadata for " + packageName);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Package metadata missing");
- continue;
- }
-
- PackageInfo packageInfo;
- try {
- int flags = PackageManager.GET_SIGNATURES;
- packageInfo = mPackageManager.getPackageInfo(packageName, flags);
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Invalid package restoring data", e);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Package missing on device");
- continue;
- }
-
- if (metaInfo.versionCode > packageInfo.versionCode) {
- // Data is from a "newer" version of the app than we have currently
- // installed. If the app has not declared that it is prepared to
- // handle this case, we do not attempt the restore.
- if ((packageInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
- String message = "Version " + metaInfo.versionCode
- + " > installed version " + packageInfo.versionCode;
- Slog.w(TAG, "Package " + packageName + ": " + message);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- packageName, message);
- continue;
- } else {
- if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
- + " > installed " + packageInfo.versionCode
- + " but restoreAnyVersion");
- }
- }
-
- if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
- Slog.w(TAG, "Signature mismatch restoring " + packageName);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Signature mismatch");
- continue;
- }
-
- if (DEBUG) Slog.v(TAG, "Package " + packageName
- + " restore version [" + metaInfo.versionCode
- + "] is compatible with installed version ["
- + packageInfo.versionCode + "]");
-
- // Then set up and bind the agent
- IBackupAgent agent = bindToAgentSynchronous(
- packageInfo.applicationInfo,
- IApplicationThread.BACKUP_MODE_INCREMENTAL);
- if (agent == null) {
- Slog.w(TAG, "Can't find backup agent for " + packageName);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Restore agent missing");
- continue;
- }
-
- // And then finally run the restore on this agent
- try {
- processOneRestore(packageInfo, metaInfo.versionCode, agent,
- mNeedFullBackup);
- ++count;
- } finally {
- // unbind and tidy up even on timeout or failure, just in case
- mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
-
- // The agent was probably running with a stub Application object,
- // which isn't a valid run mode for the main app logic. Shut
- // down the app so that next time it's launched, it gets the
- // usual full initialization. Note that this is only done for
- // full-system restores: when a single app has requested a restore,
- // it is explicitly not killed following that operation.
- if (mTargetPackage == null && (packageInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
- if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
- + packageInfo.applicationInfo.processName);
- mActivityManager.killApplicationProcess(
- packageInfo.applicationInfo.processName,
- packageInfo.applicationInfo.uid);
- }
- }
- }
-
- // if we get this far, report success to the observer
- error = 0;
- int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, count, millis);
- } catch (Exception e) {
- Slog.e(TAG, "Error in restore thread", e);
- } finally {
- if (DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
-
- try {
- mTransport.finishRestore();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error finishing restore", e);
+ if (packageName == null) {
+ Slog.e(TAG, "Error getting next restore package");
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
+ executeNextState(RestoreState.FINAL);
+ return;
+ } else if (packageName.equals("")) {
+ if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
+ int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
+ EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
+ executeNextState(RestoreState.FINAL);
+ return;
}
if (mObserver != null) {
try {
- mObserver.restoreFinished(error);
+ mObserver.onUpdate(mCount, packageName);
} catch (RemoteException e) {
- Slog.d(TAG, "Restore observer died at restoreFinished");
+ Slog.d(TAG, "Restore observer died in onUpdate");
+ mObserver = null;
}
}
- // If this was a restoreAll operation, record that this was our
- // ancestral dataset, as well as the set of apps that are possibly
- // restoreable from the dataset
- if (mTargetPackage == null && pmAgent != null) {
- mAncestralPackages = pmAgent.getRestoredPackages();
- mAncestralToken = mToken;
- writeRestoreTokens();
+ Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
+ if (metaInfo == null) {
+ Slog.e(TAG, "Missing metadata for " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
+ "Package metadata missing");
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ return;
}
- // We must under all circumstances tell the Package Manager to
- // proceed with install notifications if it's waiting for us.
- if (mPmToken > 0) {
- if (DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
- try {
- mPackageManagerBinder.finishPackageInstall(mPmToken);
- } catch (RemoteException e) { /* can't happen */ }
+ PackageInfo packageInfo;
+ try {
+ int flags = PackageManager.GET_SIGNATURES;
+ packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Invalid package restoring data", e);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
+ "Package missing on device");
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ return;
}
- // Furthermore we need to reset the session timeout clock
- mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
- mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
- TIMEOUT_RESTORE_INTERVAL);
+ if (metaInfo.versionCode > packageInfo.versionCode) {
+ // Data is from a "newer" version of the app than we have currently
+ // installed. If the app has not declared that it is prepared to
+ // handle this case, we do not attempt the restore.
+ if ((packageInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
+ String message = "Version " + metaInfo.versionCode
+ + " > installed version " + packageInfo.versionCode;
+ Slog.w(TAG, "Package " + packageName + ": " + message);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
+ packageName, message);
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ return;
+ } else {
+ if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
+ + " > installed " + packageInfo.versionCode
+ + " but restoreAnyVersion");
+ }
+ }
- // done; we can finally release the wakelock
- mWakelock.release();
+ if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
+ Slog.w(TAG, "Signature mismatch restoring " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
+ "Signature mismatch");
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ return;
+ }
+
+ if (DEBUG) Slog.v(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is compatible with installed version ["
+ + packageInfo.versionCode + "]");
+
+ // Then set up and bind the agent
+ IBackupAgent agent = bindToAgentSynchronous(
+ packageInfo.applicationInfo,
+ IApplicationThread.BACKUP_MODE_INCREMENTAL);
+ if (agent == null) {
+ Slog.w(TAG, "Can't find backup agent for " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
+ "Restore agent missing");
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ return;
+ }
+
+ // And then finally start the restore on this agent
+ try {
+ initiateOneRestore(packageInfo, metaInfo.versionCode, agent, mNeedFullBackup);
+ ++mCount;
+ } catch (Exception e) {
+ Slog.e(TAG, "Error when attempting restore: " + e.toString());
+ agentErrorCleanup();
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to fetch restore data from transport");
+ mStatus = BackupConstants.TRANSPORT_ERROR;
+ executeNextState(RestoreState.FINAL);
}
}
- // Do the guts of a restore of one application, using mTransport.getRestoreData().
- void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
+ void finalizeRestore() {
+ if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
+
+ try {
+ mTransport.finishRestore();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error finishing restore", e);
+ }
+
+ if (mObserver != null) {
+ try {
+ mObserver.restoreFinished(mStatus);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Restore observer died at restoreFinished");
+ }
+ }
+
+ // If this was a restoreAll operation, record that this was our
+ // ancestral dataset, as well as the set of apps that are possibly
+ // restoreable from the dataset
+ if (mTargetPackage == null && mPmAgent != null) {
+ mAncestralPackages = mPmAgent.getRestoredPackages();
+ mAncestralToken = mToken;
+ writeRestoreTokens();
+ }
+
+ // We must under all circumstances tell the Package Manager to
+ // proceed with install notifications if it's waiting for us.
+ if (mPmToken > 0) {
+ if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
+ try {
+ mPackageManagerBinder.finishPackageInstall(mPmToken);
+ } catch (RemoteException e) { /* can't happen */ }
+ }
+
+ // Furthermore we need to reset the session timeout clock
+ mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
+ mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
+ TIMEOUT_RESTORE_INTERVAL);
+
+ // done; we can finally release the wakelock
+ Slog.i(TAG, "Restore complete.");
+ mWakelock.release();
+ }
+
+ // Call asynchronously into the app, passing it the restore data. The next step
+ // after this is always a callback, either operationComplete() or handleTimeout().
+ void initiateOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
boolean needFullBackup) {
- // !!! TODO: actually run the restore through mTransport
+ mCurrentPackage = app;
final String packageName = app.packageName;
- if (DEBUG) Slog.d(TAG, "processOneRestore packageName=" + packageName);
+ if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
// !!! TODO: get the dirs from the transport
- File backupDataName = new File(mDataDir, packageName + ".restore");
- File newStateName = new File(mStateDir, packageName + ".new");
- File savedStateName = new File(mStateDir, packageName);
-
- ParcelFileDescriptor backupData = null;
- ParcelFileDescriptor newState = null;
+ mBackupDataName = new File(mDataDir, packageName + ".restore");
+ mNewStateName = new File(mStateDir, packageName + ".new");
+ mSavedStateName = new File(mStateDir, packageName);
final int token = generateToken();
try {
// Run the transport's restore pass
- backupData = ParcelFileDescriptor.open(backupDataName,
+ mBackupData = ParcelFileDescriptor.open(mBackupDataName,
ParcelFileDescriptor.MODE_READ_WRITE |
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
- if (mTransport.getRestoreData(backupData) != BackupConstants.TRANSPORT_OK) {
+ if (mTransport.getRestoreData(mBackupData) != BackupConstants.TRANSPORT_OK) {
Slog.e(TAG, "Error getting restore data for " + packageName);
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
return;
}
// Okay, we have the data. Now have the agent do the restore.
- backupData.close();
- backupData = ParcelFileDescriptor.open(backupDataName,
+ mBackupData.close();
+ mBackupData = ParcelFileDescriptor.open(mBackupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- newState = ParcelFileDescriptor.open(newStateName,
+ mNewState = ParcelFileDescriptor.open(mNewStateName,
ParcelFileDescriptor.MODE_READ_WRITE |
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
// Kick off the restore, checking for hung agents
- prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL);
- agent.doRestore(backupData, appVersionCode, newState, token, mBackupManagerBinder);
- boolean success = waitUntilOperationComplete(token);
-
- if (!success) {
- throw new RuntimeException("restore timeout");
- }
-
- // if everything went okay, remember the recorded state now
- //
- // !!! TODO: the restored data should be migrated on the server
- // side into the current dataset. In that case the new state file
- // we just created would reflect the data already extant in the
- // backend, so there'd be nothing more to do. Until that happens,
- // however, we need to make sure that we record the data to the
- // current backend dataset. (Yes, this means shipping the data over
- // the wire in both directions. That's bad, but consistency comes
- // first, then efficiency.) Once we introduce server-side data
- // migration to the newly-restored device's dataset, we will change
- // the following from a discard of the newly-written state to the
- // "correct" operation of renaming into the canonical state blob.
- newStateName.delete(); // TODO: remove; see above comment
- //newStateName.renameTo(savedStateName); // TODO: replace with this
-
- int size = (int) backupDataName.length();
- EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, packageName, size);
+ prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, this);
+ agent.doRestore(mBackupData, appVersionCode, mNewState, token, mBackupManagerBinder);
} catch (Exception e) {
- Slog.e(TAG, "Error restoring data for " + packageName, e);
+ Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, e.toString());
+ agentErrorCleanup(); // clears any pending timeout messages as well
- // If the agent fails restore, it might have put the app's data
- // into an incoherent state. For consistency we wipe its data
- // again in this case before propagating the exception
- clearApplicationDataSynchronous(packageName);
- } finally {
- backupDataName.delete();
- try { if (backupData != null) backupData.close(); } catch (IOException e) {}
- try { if (newState != null) newState.close(); } catch (IOException e) {}
- backupData = newState = null;
- synchronized (mCurrentOperations) {
- mCurrentOperations.delete(token);
- }
+ // After a restore failure we go back to running the queue. If there
+ // are no more packages to be restored that will be handled by the
+ // next step.
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ }
+ }
- // If we know a priori that we'll need to perform a full post-restore backup
- // pass, clear the new state file data. This means we're discarding work that
- // was just done by the app's agent, but this way the agent doesn't need to
- // take any special action based on global device state.
- if (needFullBackup) {
- newStateName.delete();
+ void agentErrorCleanup() {
+ // If the agent fails restore, it might have put the app's data
+ // into an incoherent state. For consistency we wipe its data
+ // again in this case before continuing with normal teardown
+ clearApplicationDataSynchronous(mCurrentPackage.packageName);
+ agentCleanup();
+ }
+
+ void agentCleanup() {
+ mBackupDataName.delete();
+ try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
+ try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
+ mBackupData = mNewState = null;
+
+ // if everything went okay, remember the recorded state now
+ //
+ // !!! TODO: the restored data should be migrated on the server
+ // side into the current dataset. In that case the new state file
+ // we just created would reflect the data already extant in the
+ // backend, so there'd be nothing more to do. Until that happens,
+ // however, we need to make sure that we record the data to the
+ // current backend dataset. (Yes, this means shipping the data over
+ // the wire in both directions. That's bad, but consistency comes
+ // first, then efficiency.) Once we introduce server-side data
+ // migration to the newly-restored device's dataset, we will change
+ // the following from a discard of the newly-written state to the
+ // "correct" operation of renaming into the canonical state blob.
+ mNewStateName.delete(); // TODO: remove; see above comment
+ //mNewStateName.renameTo(mSavedStateName); // TODO: replace with this
+
+ // If this wasn't the PM pseudopackage, tear down the agent side
+ if (mCurrentPackage.applicationInfo != null) {
+ // unbind and tidy up even on timeout or failure
+ try {
+ mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
+
+ // The agent was probably running with a stub Application object,
+ // which isn't a valid run mode for the main app logic. Shut
+ // down the app so that next time it's launched, it gets the
+ // usual full initialization. Note that this is only done for
+ // full-system restores: when a single app has requested a restore,
+ // it is explicitly not killed following that operation.
+ if (mTargetPackage == null && (mCurrentPackage.applicationInfo.flags
+ & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
+ if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
+ + mCurrentPackage.applicationInfo.processName);
+ mActivityManager.killApplicationProcess(
+ mCurrentPackage.applicationInfo.processName,
+ mCurrentPackage.applicationInfo.uid);
+ }
+ } catch (RemoteException e) {
+ // can't happen; we run in the same process as the activity manager
}
}
+
+ // The caller is responsible for reestablishing the state machine; our
+ // responsibility here is to clear the decks for whatever comes next.
+ mBackupHandler.removeMessages(MSG_TIMEOUT, this);
+ synchronized (mCurrentOpLock) {
+ mCurrentOperations.clear();
+ }
+ }
+
+ // A call to agent.doRestore() has been positively acknowledged as complete
+ @Override
+ public void operationComplete() {
+ int size = (int) mBackupDataName.length();
+ EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, mCurrentPackage.packageName, size);
+ // Just go back to running the restore queue
+ agentCleanup();
+
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ }
+
+ // A call to agent.doRestore() has timed out
+ @Override
+ public void handleTimeout() {
+ Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
+ mCurrentPackage.packageName, "restore timeout");
+ // Handle like an agent that threw on invocation: wipe it and go on to the next
+ agentErrorCleanup();
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ }
+
+ void executeNextState(RestoreState nextState) {
+ if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
+ + this + " nextState=" + nextState);
+ mCurrentState = nextState;
+ Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
+ mBackupHandler.sendMessage(msg);
}
}
@@ -4884,12 +5279,23 @@
// Note that a currently-active backup agent has notified us that it has
// completed the given outstanding asynchronous backup/restore operation.
+ @Override
public void opComplete(int token) {
+ if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
+ Operation op = null;
synchronized (mCurrentOpLock) {
- if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
- mCurrentOperations.put(token, OP_ACKNOWLEDGED);
+ op = mCurrentOperations.get(token);
+ if (op != null) {
+ op.state = OP_ACKNOWLEDGED;
+ }
mCurrentOpLock.notifyAll();
}
+
+ // The completion callback, if any, is invoked on the handler
+ if (op != null && op.callback != null) {
+ Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
+ mBackupHandler.sendMessage(msg);
+ }
}
// ----- Restore session -----
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 00aa14c..d806309 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -454,7 +454,7 @@
}
}
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -484,7 +484,7 @@
synchronized (mVolumeStates) {
Set<String> keys = mVolumeStates.keySet();
count = keys.size();
- paths = (String[])keys.toArray(new String[count]);
+ paths = keys.toArray(new String[count]);
states = new String[count];
for (int i = 0; i < count; i++) {
states[i] = mVolumeStates.get(paths[i]);
@@ -1761,6 +1761,37 @@
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
+ @Override
+ public int getEncryptionState() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
+ "no permission to access the crypt keeper");
+
+ waitForReady();
+
+ try {
+ ArrayList<String> rsp = mConnector.doCommand("cryptfs cryptocomplete");
+ String[] tokens = rsp.get(0).split(" ");
+
+ if (tokens == null || tokens.length != 2) {
+ // Unexpected.
+ Slog.w(TAG, "Unexpected result from cryptfs cryptocomplete");
+ return ENCRYPTION_STATE_ERROR_UNKNOWN;
+ }
+
+ return Integer.parseInt(tokens[1]);
+
+ } catch (NumberFormatException e) {
+ // Bad result - unexpected.
+ Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
+ return ENCRYPTION_STATE_ERROR_UNKNOWN;
+ } catch (NativeDaemonConnectorException e) {
+ // Something bad happened.
+ Slog.w(TAG, "Error in communicating with cryptfs in validating");
+ return ENCRYPTION_STATE_ERROR_UNKNOWN;
+ }
+ }
+
+ @Override
public int decryptStorage(String password) {
if (TextUtils.isEmpty(password)) {
throw new IllegalArgumentException("password cannot be empty");
@@ -2090,7 +2121,7 @@
public void execute(ObbActionHandler handler) {
try {
if (DEBUG_OBB)
- Slog.i(TAG, "Starting to execute action: " + this.toString());
+ Slog.i(TAG, "Starting to execute action: " + toString());
mRetries++;
if (mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
@@ -2147,7 +2178,7 @@
}
class MountObbAction extends ObbAction {
- private String mKey;
+ private final String mKey;
MountObbAction(ObbState obbState, String key) {
super(obbState);
@@ -2258,7 +2289,7 @@
}
class UnmountObbAction extends ObbAction {
- private boolean mForceUnmount;
+ private final boolean mForceUnmount;
UnmountObbAction(ObbState obbState, boolean force) {
super(obbState);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 1497511..349b4d2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -98,6 +98,7 @@
public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
/** {@link #mStatsXtUid} headers. */
+ private static final String KEY_IDX = "idx";
private static final String KEY_IFACE = "iface";
private static final String KEY_UID = "uid_tag_int";
private static final String KEY_COUNTER_SET = "cnt_set";
@@ -1323,18 +1324,22 @@
// TODO: remove knownLines check once 5087722 verified
final HashSet<String> knownLines = Sets.newHashSet();
+ // TODO: remove lastIdx check once 5270106 verified
+ int lastIdx;
final ArrayList<String> keys = Lists.newArrayList();
final ArrayList<String> values = Lists.newArrayList();
final HashMap<String, String> parsed = Maps.newHashMap();
BufferedReader reader = null;
+ String line = null;
try {
reader = new BufferedReader(new FileReader(mStatsXtUid));
// parse first line as header
- String line = reader.readLine();
+ line = reader.readLine();
splitLine(line, keys);
+ lastIdx = 1;
// parse remaining lines
while ((line = reader.readLine()) != null) {
@@ -1342,32 +1347,35 @@
parseLine(keys, values, parsed);
if (!knownLines.add(line)) {
- throw new IllegalStateException("encountered duplicate proc entry");
+ throw new IllegalStateException("duplicate proc entry: " + line);
}
- try {
- entry.iface = parsed.get(KEY_IFACE);
- entry.uid = getParsedInt(parsed, KEY_UID);
- entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
- entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
- entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
- entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
- entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
- entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
+ final int idx = getParsedInt(parsed, KEY_IDX);
+ if (idx != lastIdx + 1) {
+ throw new IllegalStateException(
+ "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
+ }
+ lastIdx = idx;
- if (limitUid == UID_ALL || limitUid == entry.uid) {
- stats.addValues(entry);
- }
- } catch (NumberFormatException e) {
- Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
+ entry.iface = parsed.get(KEY_IFACE);
+ entry.uid = getParsedInt(parsed, KEY_UID);
+ entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
+ entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
+ entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
+ entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
+ entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
+ entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
+
+ if (limitUid == UID_ALL || limitUid == entry.uid) {
+ stats.addValues(entry);
}
}
} catch (NullPointerException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
+ throw new IllegalStateException("problem parsing line: " + line, e);
} catch (NumberFormatException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
+ throw new IllegalStateException("problem parsing line: " + line, e);
} catch (IOException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
+ throw new IllegalStateException("problem parsing line: " + line, e);
} finally {
IoUtils.closeQuietly(reader);
}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index ca3b12d..bab9f8a 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -301,7 +301,7 @@
// also allows calls from window manager which is in this process.
enforceStatusBarService();
- if (SPEW) Slog.d(TAG, "setSystemUiVisibility(" + vis + ")");
+ if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
synchronized (mLock) {
updateUiVisibilityLocked(vis);
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 4447ad0..bc256ed 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -383,7 +383,7 @@
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- LinkCapabilities linkCapabilities, int networkType) {
+ LinkCapabilities linkCapabilities, int networkType, boolean roaming) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
@@ -437,7 +437,7 @@
}
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- apnType, linkProperties, linkCapabilities);
+ apnType, linkProperties, linkCapabilities, roaming);
}
public void notifyDataConnectionFailed(String reason, String apnType) {
@@ -596,7 +596,7 @@
private void broadcastDataConnectionStateChanged(int state,
boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- LinkCapabilities linkCapabilities) {
+ LinkCapabilities linkCapabilities, boolean roaming) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -618,6 +618,8 @@
if (linkCapabilities != null) {
intent.putExtra(Phone.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
}
+ if (roaming) intent.putExtra(Phone.DATA_NETWORK_ROAMING_KEY, true);
+
intent.putExtra(Phone.DATA_APN_KEY, apn);
intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType);
mContext.sendStickyBroadcast(intent);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index a80a2b8..e6b5898 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -37,7 +37,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiWatchdogStateMachine;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WpsConfiguration;
+import android.net.wifi.Wps;
import android.net.wifi.WpsResult;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
@@ -286,7 +286,7 @@
}
case WifiManager.CMD_START_WPS: {
//replyTo has the original source
- mWifiStateMachine.startWps(msg.replyTo, (WpsConfiguration)msg.obj);
+ mWifiStateMachine.startWps(msg.replyTo, (Wps)msg.obj);
break;
}
case WifiManager.CMD_DISABLE_NETWORK: {
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index e45c368..6a63eac 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -107,25 +107,18 @@
private synchronized final void updateState(String name, int state)
{
if (name.equals("usb_audio")) {
- if (state == 1) {
- switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
- BIT_USB_HEADSET_DGTL|BIT_HDMI_AUDIO)) |
- (state << 2));
- } else if (state == 2) {
- switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
- BIT_USB_HEADSET_ANLG|BIT_HDMI_AUDIO)) |
- (state << 3));
- } else switchState = (mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO));
- }
- else if (name.equals("hdmi")) {
+ switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO)) |
+ ((state == 1) ? BIT_USB_HEADSET_ANLG :
+ ((state == 2) ? BIT_USB_HEADSET_DGTL : 0)));
+ } else if (name.equals("hdmi")) {
switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
BIT_USB_HEADSET_DGTL|BIT_USB_HEADSET_ANLG)) |
- (state << 4));
- }
- else {
+ ((state == 1) ? BIT_HDMI_AUDIO : 0));
+ } else {
switchState = ((mHeadsetState & (BIT_HDMI_AUDIO|BIT_USB_HEADSET_ANLG|
BIT_USB_HEADSET_DGTL)) |
- state);
+ ((state == 1) ? BIT_HEADSET :
+ ((state == 2) ? BIT_HEADSET_NO_MIC : 0)));
}
update(name, switchState);
}
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index eb399ad..aa43bb6 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -203,6 +203,7 @@
}
case 1: {
mSendHoverDelayed.remove();
+ mPerformLongPressDelayed.remove();
// Send a hover for every finger down so the user gets feedback.
final int pointerId = pointerTracker.getPrimaryActivePointerId();
final int pointerIdBits = (1 << pointerId);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9db56ce..41af137 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -106,6 +106,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.EventLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.Log;
import android.util.PrintWriterPrinter;
@@ -3326,20 +3327,28 @@
boolean didSomething = killPackageProcessesLocked(name, uid, -100,
callerWillRestart, false, doit, evenPersistent);
- for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ TaskRecord lastTask = null;
+ for (i=0; i<mMainStack.mHistory.size(); i++) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.packageName.equals(name)
+ final boolean samePackage = r.packageName.equals(name);
+ if ((samePackage || r.task == lastTask)
&& (r.app == null || evenPersistent || !r.app.persistent)) {
if (!doit) {
return true;
}
didSomething = true;
Slog.i(TAG, " Force finishing activity " + r);
- if (r.app != null) {
- r.app.removed = true;
+ if (samePackage) {
+ if (r.app != null) {
+ r.app.removed = true;
+ }
+ r.app = null;
}
- r.app = null;
- r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
+ lastTask = r.task;
+ if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+ null, "force-stop")) {
+ i--;
+ }
}
}
@@ -5004,7 +5013,13 @@
maxNum < N ? maxNum : N);
for (int i=0; i<N && maxNum > 0; i++) {
TaskRecord tr = mRecentTasks.get(i);
- if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
+ // Return the entry if desired by the caller. We always return
+ // the first entry, because callers always expect this to be the
+ // forground app. We may filter others if the caller has
+ // not supplied RECENT_WITH_EXCLUDED and there is some reason
+ // we should exclude the entry.
+ if (i == 0
+ || ((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
|| (tr.intent == null)
|| ((tr.intent.getFlags()
&Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
@@ -5152,6 +5167,29 @@
cleanUpRemovedTaskLocked(r,
(flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0);
return true;
+ } else {
+ TaskRecord tr = null;
+ int i=0;
+ while (i < mRecentTasks.size()) {
+ TaskRecord t = mRecentTasks.get(i);
+ if (t.taskId == taskId) {
+ tr = t;
+ break;
+ }
+ i++;
+ }
+ if (tr != null) {
+ if (tr.numActivities <= 0) {
+ // Caller is just removing a recent task that is
+ // not actively running. That is easy!
+ mRecentTasks.remove(i);
+ } else {
+ Slog.w(TAG, "removeTask: task " + taskId
+ + " does not have activities to remove, "
+ + " but numActivities=" + tr.numActivities
+ + ": " + tr);
+ }
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -7546,7 +7584,33 @@
return errList;
}
-
+
+ static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) {
+ if (adj >= ProcessList.EMPTY_APP_ADJ) {
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
+ } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+ if (currApp != null) {
+ currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
+ }
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ } else if (adj >= ProcessList.HOME_APP_ADJ) {
+ if (currApp != null) {
+ currApp.lru = 0;
+ }
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) {
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
+ } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
+ } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
+ } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+ } else {
+ return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+ }
+ }
+
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
// Lazy instantiation of list
List<ActivityManager.RunningAppProcessInfo> runList = null;
@@ -7567,28 +7631,12 @@
currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
}
int adj = app.curAdj;
- if (adj >= ProcessList.EMPTY_APP_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
- } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
- currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
- } else if (adj >= ProcessList.HOME_APP_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
- currApp.lru = 0;
- } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
- } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
- } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
- } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
- } else {
- currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
- }
+ currApp.importance = oomAdjToImportance(adj, currApp);
currApp.importanceReasonCode = app.adjTypeCode;
if (app.adjSource instanceof ProcessRecord) {
currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
+ currApp.importanceReasonImportance = oomAdjToImportance(
+ app.adjSourceOom, null);
} else if (app.adjSource instanceof ActivityRecord) {
ActivityRecord r = (ActivityRecord)app.adjSource;
if (r.app != null) currApp.importanceReasonPid = r.app.pid;
@@ -7891,7 +7939,7 @@
if (mLruProcesses.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
- pw.println(" Process LRU list (most recent first):");
+ pw.println(" Process LRU list (sorted by oom_adj):");
dumpProcessOomList(pw, this, mLruProcesses, " ",
"Proc", "PERS", false);
needSep = true;
@@ -8069,29 +8117,6 @@
boolean needSep = false;
if (mLruProcesses.size() > 0) {
- ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mLruProcesses);
-
- Comparator<ProcessRecord> comparator = new Comparator<ProcessRecord>() {
- @Override
- public int compare(ProcessRecord object1, ProcessRecord object2) {
- if (object1.setAdj != object2.setAdj) {
- return object1.setAdj > object2.setAdj ? -1 : 1;
- }
- if (object1.setSchedGroup != object2.setSchedGroup) {
- return object1.setSchedGroup > object2.setSchedGroup ? -1 : 1;
- }
- if (object1.keeping != object2.keeping) {
- return object1.keeping ? -1 : 1;
- }
- if (object1.pid != object2.pid) {
- return object1.pid > object2.pid ? -1 : 1;
- }
- return 0;
- }
- };
-
- Collections.sort(procs, comparator);
-
if (needSep) pw.println(" ");
needSep = true;
pw.println(" OOM levels:");
@@ -8110,7 +8135,7 @@
if (needSep) pw.println(" ");
needSep = true;
pw.println(" Process OOM control:");
- dumpProcessOomList(pw, this, procs, " ",
+ dumpProcessOomList(pw, this, mLruProcesses, " ",
"Proc", "PERS", true);
needSep = true;
}
@@ -8859,10 +8884,33 @@
}
private static final void dumpProcessOomList(PrintWriter pw,
- ActivityManagerService service, List<ProcessRecord> list,
+ ActivityManagerService service, List<ProcessRecord> origList,
String prefix, String normalLabel, String persistentLabel,
boolean inclDetails) {
+ ArrayList<Pair<ProcessRecord, Integer>> list
+ = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
+ for (int i=0; i<origList.size(); i++) {
+ list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
+ }
+
+ Comparator<Pair<ProcessRecord, Integer>> comparator
+ = new Comparator<Pair<ProcessRecord, Integer>>() {
+ @Override
+ public int compare(Pair<ProcessRecord, Integer> object1,
+ Pair<ProcessRecord, Integer> object2) {
+ if (object1.first.setAdj != object2.first.setAdj) {
+ return object1.first.setAdj > object2.first.setAdj ? -1 : 1;
+ }
+ if (object1.second.intValue() != object2.second.intValue()) {
+ return object1.second.intValue() > object2.second.intValue() ? -1 : 1;
+ }
+ return 0;
+ }
+ };
+
+ Collections.sort(list, comparator);
+
final long curRealtime = SystemClock.elapsedRealtime();
final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime;
final long curUptime = SystemClock.uptimeMillis();
@@ -8870,7 +8918,7 @@
final int N = list.size()-1;
for (int i=N; i>=0; i--) {
- ProcessRecord r = list.get(i);
+ ProcessRecord r = list.get(i).first;
String oomAdj;
if (r.setAdj >= ProcessList.EMPTY_APP_ADJ) {
oomAdj = buildOomTag("empty", null, r.setAdj, ProcessList.EMPTY_APP_ADJ);
@@ -8919,7 +8967,7 @@
}
pw.println(String.format("%s%s #%2d: adj=%s/%s%s trm=%2d %s (%s)",
prefix, (r.persistent ? persistentLabel : normalLabel),
- N-i, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
+ N-list.get(i).second, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
pw.print(prefix);
@@ -13118,6 +13166,7 @@
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client;
+ app.adjSourceOom = clientAdj;
app.adjTarget = s.name;
}
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
@@ -13140,6 +13189,7 @@
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = a;
+ app.adjSourceOom = adj;
app.adjTarget = s.name;
}
}
@@ -13201,6 +13251,7 @@
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
+ app.adjSourceOom = clientAdj;
app.adjTarget = cpr.name;
}
if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
@@ -13511,16 +13562,21 @@
computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
if (app.curRawAdj != app.setRawAdj) {
- if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
- && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
- // If this app is transitioning from foreground to
- // non-foreground, have it do a gc.
- scheduleAppGcLocked(app);
- } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
- && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
- // Likewise do a gc when an app is moving in to the
- // background (such as a service stopping).
- scheduleAppGcLocked(app);
+ if (false) {
+ // Removing for now. Forcing GCs is not so useful anymore
+ // with Dalvik, and the new memory level hint facility is
+ // better for what we need to do these days.
+ if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
+ && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ // If this app is transitioning from foreground to
+ // non-foreground, have it do a gc.
+ scheduleAppGcLocked(app);
+ } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+ && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
+ // Likewise do a gc when an app is moving in to the
+ // background (such as a service stopping).
+ scheduleAppGcLocked(app);
+ }
}
if (wasKeeping && !app.keeping) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 4ad0f45..a0aedf9 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1151,6 +1151,7 @@
try {
mService.mWindowManager.setAppVisibility(r, true);
r.sleeping = false;
+ r.app.pendingUiClean = true;
r.app.thread.scheduleWindowVisibility(r, true);
r.stopFreezingScreenLocked(false);
} catch (Exception e) {
@@ -1497,6 +1498,7 @@
next.sleeping = false;
showAskCompatModeDialogLocked(next);
+ next.app.pendingUiClean = true;
next.app.thread.scheduleResumeActivity(next,
mService.isNextTransitionForward());
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 24d92cf..9392bb4 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -99,6 +99,7 @@
String adjType; // Debugging: primary thing impacting oom_adj.
int adjTypeCode; // Debugging: adj code to report to app.
Object adjSource; // Debugging: option dependent object.
+ int adjSourceOom; // Debugging: oom_adj of adjSource's process.
Object adjTarget; // Debugging: target component impacting oom_adj.
// contains HistoryRecord objects
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 8af90ff..9067fae 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -100,6 +100,7 @@
import android.telephony.TelephonyManager;
import android.text.format.Formatter;
import android.text.format.Time;
+import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.Slog;
import android.util.SparseArray;
@@ -298,18 +299,9 @@
try {
mActivityManager.registerProcessObserver(mProcessObserver);
- } catch (RemoteException e) {
- // ouch, no foregroundActivities updates means some processes may
- // never get network access.
- Slog.e(TAG, "unable to register IProcessObserver", e);
- }
-
- try {
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
- // ouch, no alert updates means we fall back to
- // ACTION_NETWORK_STATS_UPDATED broadcasts.
- Slog.e(TAG, "unable to register INetworkManagementEventObserver", e);
+ // ignored; both services live in system_server
}
// TODO: traverse existing processes to know foreground state, or have
@@ -462,7 +454,7 @@
// caused alert to trigger.
mNetworkStats.forceUpdate();
} catch (RemoteException e) {
- Slog.w(TAG, "problem updating network stats");
+ // ignored; service lives in system_server
}
updateNetworkEnabledLocked();
@@ -495,9 +487,7 @@
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
-
final long totalBytes = getTotalBytes(policy.template, start, end);
- if (totalBytes == UNKNOWN_BYTES) continue;
if (policy.limitBytes != LIMIT_DISABLED && totalBytes >= policy.limitBytes) {
if (policy.lastSnooze >= start) {
@@ -671,7 +661,7 @@
packageName, tag, 0x0, builder.getNotification(), idReceived);
mActiveNotifs.add(tag);
} catch (RemoteException e) {
- Slog.w(TAG, "problem during enqueueNotification: " + e);
+ // ignored; service lives in system_server
}
}
@@ -705,7 +695,7 @@
0x0, builder.getNotification(), idReceived);
mActiveNotifs.add(tag);
} catch (RemoteException e) {
- Slog.w(TAG, "problem during enqueueNotification: " + e);
+ // ignored; service lives in system_server
}
}
@@ -716,7 +706,7 @@
mNotifManager.cancelNotificationWithTag(
packageName, tag, 0x0);
} catch (RemoteException e) {
- Slog.w(TAG, "problem during enqueueNotification: " + e);
+ // ignored; service lives in system_server
}
}
@@ -758,9 +748,7 @@
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
-
final long totalBytes = getTotalBytes(policy.template, start, end);
- if (totalBytes == UNKNOWN_BYTES) continue;
// disable data connection when over limit and not snoozed
final boolean overLimit = policy.limitBytes != LIMIT_DISABLED
@@ -810,7 +798,7 @@
try {
states = mConnManager.getAllNetworkState();
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading network state");
+ // ignored; service lives in system_server
return;
}
@@ -857,9 +845,7 @@
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
-
final long totalBytes = getTotalBytes(policy.template, start, end);
- if (totalBytes == UNKNOWN_BYTES) continue;
if (LOGD) {
Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
@@ -1006,9 +992,9 @@
// missing policy is okay, probably first boot
upgradeLegacyBackgroundData();
} catch (IOException e) {
- Slog.e(TAG, "problem reading network stats", e);
+ Log.wtf(TAG, "problem reading network policy", e);
} catch (XmlPullParserException e) {
- Slog.e(TAG, "problem reading network stats", e);
+ Log.wtf(TAG, "problem reading network policy", e);
} finally {
IoUtils.closeQuietly(fis);
}
@@ -1246,12 +1232,10 @@
final long currentTime = currentTimeMillis(false);
+ // find total bytes used under policy
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
-
- // find total bytes used under policy
final long totalBytes = getTotalBytes(policy.template, start, end);
- if (totalBytes == UNKNOWN_BYTES) return null;
// report soft and hard limits under policy
final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
@@ -1369,6 +1353,7 @@
try {
mScreenOn = mPowerManager.isScreenOn();
} catch (RemoteException e) {
+ // ignored; service lives in system_server
}
updateRulesForScreenLocked();
}
@@ -1448,7 +1433,7 @@
// adjust stats accounting based on foreground status
mNetworkStats.setUidForeground(uid, uidForeground);
} catch (RemoteException e) {
- Slog.w(TAG, "problem dispatching foreground change");
+ // ignored; service lives in system_server
}
}
@@ -1498,9 +1483,9 @@
try {
mNetworkManager.setInterfaceQuota(iface, quotaBytes);
} catch (IllegalStateException e) {
- Slog.e(TAG, "problem setting interface quota", e);
+ Log.wtf(TAG, "problem setting interface quota", e);
} catch (RemoteException e) {
- Slog.e(TAG, "problem setting interface quota", e);
+ // ignored; service lives in system_server
}
}
@@ -1508,29 +1493,9 @@
try {
mNetworkManager.removeInterfaceQuota(iface);
} catch (IllegalStateException e) {
- Slog.e(TAG, "problem removing interface quota", e);
+ Log.wtf(TAG, "problem removing interface quota", e);
} catch (RemoteException e) {
- Slog.e(TAG, "problem removing interface quota", e);
- }
- }
-
- private void setInterfaceAlert(String iface, long alertBytes) {
- try {
- mNetworkManager.setInterfaceAlert(iface, alertBytes);
- } catch (IllegalStateException e) {
- Slog.e(TAG, "problem setting interface alert", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "problem setting interface alert", e);
- }
- }
-
- private void removeInterfaceAlert(String iface) {
- try {
- mNetworkManager.removeInterfaceAlert(iface);
- } catch (IllegalStateException e) {
- Slog.e(TAG, "problem removing interface alert", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "problem removing interface alert", e);
+ // ignored; service lives in system_server
}
}
@@ -1538,9 +1503,9 @@
try {
mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
} catch (IllegalStateException e) {
- Slog.e(TAG, "problem setting uid rules", e);
+ Log.wtf(TAG, "problem setting uid rules", e);
} catch (RemoteException e) {
- Slog.e(TAG, "problem setting uid rules", e);
+ // ignored; service lives in system_server
}
}
@@ -1556,7 +1521,7 @@
try {
mConnManager.setPolicyDataEnable(networkType, enabled);
} catch (RemoteException e) {
- Slog.e(TAG, "problem setting network enabled", e);
+ // ignored; service lives in system_server
}
mActiveNetworkEnabled.put(networkType, enabled);
@@ -1569,8 +1534,6 @@
return telephony.getSubscriberId();
}
- private static final long UNKNOWN_BYTES = -1;
-
private long getTotalBytes(NetworkTemplate template, long start, long end) {
try {
final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
@@ -1578,8 +1541,8 @@
final NetworkStats.Entry entry = stats.getValues(0, null);
return entry.rxBytes + entry.txBytes;
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading summary for template " + template);
- return UNKNOWN_BYTES;
+ // ignored; service lives in system_server
+ return 0;
}
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 4d54fd4..af29d85 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -79,6 +79,7 @@
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.EventLog;
+import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -128,7 +129,16 @@
private static final int VERSION_UID_WITH_SET = 4;
private static final int MSG_PERFORM_POLL = 0x1;
- private static final int MSG_PERFORM_POLL_DETAILED = 0x2;
+
+ /** Flags to control detail level of poll event. */
+ private static final int FLAG_POLL_NETWORK = 0x1;
+ private static final int FLAG_POLL_UID = 0x2;
+ private static final int FLAG_PERSIST_NETWORK = 0x10;
+ private static final int FLAG_PERSIST_UID = 0x20;
+ private static final int FLAG_FORCE_PERSIST = 0x100;
+
+ private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID;
+ private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
private final Context mContext;
private final INetworkManagementService mNetworkManager;
@@ -261,9 +271,7 @@
try {
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
- // ouch, no push updates means we fall back to
- // ACTION_NETWORK_STATS_POLL intervals.
- Slog.e(TAG, "unable to register INetworkManagementEventObserver", e);
+ // ignored; service lives in system_server
}
registerPollAlarmLocked();
@@ -305,7 +313,7 @@
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
mSettings.getPollInterval(), mPollIntent);
} catch (RemoteException e) {
- Slog.w(TAG, "problem registering for poll alarm: " + e);
+ // ignored; service lives in system_server
}
}
@@ -321,7 +329,7 @@
} catch (IllegalStateException e) {
Slog.w(TAG, "problem registering for global alert: " + e);
} catch (RemoteException e) {
- Slog.w(TAG, "problem registering for global alert: " + e);
+ // ignored; service lives in system_server
}
}
@@ -509,7 +517,7 @@
@Override
public void forceUpdate() {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- performPoll(true, false);
+ performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL);
}
/**
@@ -538,7 +546,7 @@
public void onReceive(Context context, Intent intent) {
// on background handler thread, and verified UPDATE_DEVICE_STATS
// permission above.
- performPoll(true, false);
+ performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL);
// verify that we're watching global alert
registerGlobalAlert();
@@ -585,7 +593,8 @@
if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
// kick off background poll to collect network stats; UID stats
// are handled during normal polling interval.
- mHandler.obtainMessage(MSG_PERFORM_POLL).sendToTarget();
+ final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK;
+ mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
// re-arm global alert for next update
registerGlobalAlert();
@@ -605,13 +614,17 @@
// take one last stats snapshot before updating iface mapping. this
// isn't perfect, since the kernel may already be counting traffic from
// the updated network.
- performPollLocked(false, false);
+
+ // poll both network and UID stats, but only persist network stats,
+ // since this codepath should stay fast. UID stats will be persisted
+ // during next alarm poll event.
+ performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK);
final NetworkState[] states;
try {
states = mConnManager.getAllNetworkState();
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading network state");
+ // ignored; service lives in system_server
return;
}
@@ -646,15 +659,15 @@
} catch (IllegalStateException e) {
Slog.w(TAG, "problem reading network stats: " + e);
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
+ // ignored; service lives in system_server
}
}
- private void performPoll(boolean detailedPoll, boolean forcePersist) {
+ private void performPoll(int flags) {
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- performPollLocked(detailedPoll, forcePersist);
+ performPollLocked(flags);
} finally {
mWakeLock.release();
}
@@ -664,14 +677,17 @@
/**
* Periodic poll operation, reading current statistics and recording into
* {@link NetworkStatsHistory}.
- *
- * @param detailedPoll Indicate if detailed UID stats should be collected
- * during this poll operation.
*/
- private void performPollLocked(boolean detailedPoll, boolean forcePersist) {
- if (LOGV) Slog.v(TAG, "performPollLocked()");
+ private void performPollLocked(int flags) {
+ if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
final long startRealtime = SystemClock.elapsedRealtime();
+ final boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0;
+ final boolean pollUid = (flags & FLAG_POLL_UID) != 0;
+ final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
+ final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
+ final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0;
+
// try refreshing time source when stale
if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
mTime.forceRefresh();
@@ -680,41 +696,40 @@
// TODO: consider marking "untrusted" times in historical stats
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- final long persistThreshold = mSettings.getPersistThreshold();
+ final long threshold = mSettings.getPersistThreshold();
- final NetworkStats networkSnapshot;
- final NetworkStats uidSnapshot;
try {
- networkSnapshot = mNetworkManager.getNetworkStatsSummary();
- uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsUidDetail(UID_ALL) : null;
- } catch (IllegalStateException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
- return;
- }
+ if (pollNetwork) {
+ final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary();
+ performNetworkPollLocked(networkSnapshot, currentTime);
- performNetworkPollLocked(networkSnapshot, currentTime);
-
- // persist when enough network data has occurred
- final NetworkStats persistNetworkDelta = computeStatsDelta(
- mLastPersistNetworkSnapshot, networkSnapshot, true);
- if (forcePersist || persistNetworkDelta.getTotalBytes() > persistThreshold) {
- writeNetworkStatsLocked();
- mLastPersistNetworkSnapshot = networkSnapshot;
- }
-
- if (detailedPoll) {
- performUidPollLocked(uidSnapshot, currentTime);
-
- // persist when enough network data has occurred
- final NetworkStats persistUidDelta = computeStatsDelta(
- mLastPersistUidSnapshot, uidSnapshot, true);
- if (forcePersist || persistUidDelta.getTotalBytes() > persistThreshold) {
- writeUidStatsLocked();
- mLastPersistUidSnapshot = networkSnapshot;
+ // persist when enough network data has occurred
+ final NetworkStats persistNetworkDelta = computeStatsDelta(
+ mLastPersistNetworkSnapshot, networkSnapshot, true);
+ final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold;
+ if (forcePersist || (persistNetwork && pastThreshold)) {
+ writeNetworkStatsLocked();
+ mLastPersistNetworkSnapshot = networkSnapshot;
+ }
}
+
+ if (pollUid) {
+ final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
+ performUidPollLocked(uidSnapshot, currentTime);
+
+ // persist when enough network data has occurred
+ final NetworkStats persistUidDelta = computeStatsDelta(
+ mLastPersistUidSnapshot, uidSnapshot, true);
+ final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold;
+ if (forcePersist || (persistUid && pastThreshold)) {
+ writeUidStatsLocked();
+ mLastPersistUidSnapshot = uidSnapshot;
+ }
+ }
+ } catch (IllegalStateException e) {
+ Log.wtf(TAG, "problem reading network stats", e);
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
}
if (LOGV) {
@@ -722,8 +737,8 @@
Slog.v(TAG, "performPollLocked() took " + duration + "ms");
}
- // sample stats after detailed poll
- if (detailedPoll) {
+ // sample stats after each full poll
+ if (pollNetwork && pollUid) {
performSample();
}
@@ -785,6 +800,10 @@
entry = delta.getValues(i, entry);
final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
if (ident == null) {
+ if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
+ || entry.txPackets > 0) {
+ Log.w(TAG, "dropping UID delta from unknown iface: " + entry);
+ }
continue;
}
@@ -959,7 +978,7 @@
} catch (FileNotFoundException e) {
// missing stats is okay, probably first boot
} catch (IOException e) {
- Slog.e(TAG, "problem reading network stats", e);
+ Log.wtf(TAG, "problem reading network stats", e);
} finally {
IoUtils.closeQuietly(in);
}
@@ -1032,7 +1051,7 @@
} catch (FileNotFoundException e) {
// missing stats is okay, probably first boot
} catch (IOException e) {
- Slog.e(TAG, "problem reading uid stats", e);
+ Log.wtf(TAG, "problem reading uid stats", e);
} finally {
IoUtils.closeQuietly(in);
}
@@ -1061,7 +1080,7 @@
out.flush();
mNetworkFile.finishWrite(fos);
} catch (IOException e) {
- Slog.w(TAG, "problem writing stats: ", e);
+ Log.wtf(TAG, "problem writing stats", e);
if (fos != null) {
mNetworkFile.failWrite(fos);
}
@@ -1115,7 +1134,7 @@
out.flush();
mUidFile.finishWrite(fos);
} catch (IOException e) {
- Slog.w(TAG, "problem writing stats: ", e);
+ Log.wtf(TAG, "problem writing stats", e);
if (fos != null) {
mUidFile.failWrite(fos);
}
@@ -1142,7 +1161,7 @@
}
if (argSet.contains("poll")) {
- performPollLocked(true, true);
+ performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST);
pw.println("Forced poll");
return;
}
@@ -1273,11 +1292,8 @@
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERFORM_POLL: {
- performPoll(false, false);
- return true;
- }
- case MSG_PERFORM_POLL_DETAILED: {
- performPoll(true, false);
+ final int flags = msg.arg1;
+ performPoll(flags);
return true;
}
default: {
@@ -1349,7 +1365,7 @@
return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
}
public long getPersistThreshold() {
- return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 512 * KB_IN_BYTES);
+ return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
}
public long getNetworkBucketDuration() {
return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 3c475a0..e25638f 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -304,8 +304,12 @@
}
if (!mStarted) {
- mEnterAnimation.setStartTime(now);
- mExitAnimation.setStartTime(now);
+ if (mEnterAnimation != null) {
+ mEnterAnimation.setStartTime(now);
+ }
+ if (mExitAnimation != null) {
+ mExitAnimation.setStartTime(now);
+ }
mStarted = true;
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 755a268..df9698e 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -774,7 +774,7 @@
// The window manager only throws security exceptions, so let's
// log all others.
if (!(e instanceof SecurityException)) {
- Slog.e(TAG, "Window Manager Crash", e);
+ Log.wtf(TAG, "Window Manager Crash", e);
}
throw e;
}
@@ -5824,27 +5824,6 @@
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
- // We need to determine the smallest width that will occur under normal
- // operation. To this, start with the base screen size and compute the
- // width under the different possible rotations. We need to un-rotate
- // the current screen dimensions before doing this.
- int unrotDw, unrotDh;
- if (rotated) {
- unrotDw = dh;
- unrotDh = dw;
- } else {
- unrotDw = dw;
- unrotDh = dh;
- }
- config.smallestScreenWidthDp = reduceConfigWidthSize(unrotDw,
- Surface.ROTATION_0, dm.density, unrotDw);
- config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
- Surface.ROTATION_90, dm.density, unrotDh);
- config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
- Surface.ROTATION_180, dm.density, unrotDw);
- config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
- Surface.ROTATION_270, dm.density, unrotDh);
-
// Compute the screen layout size class.
int screenLayout;
int longSize = dw;
@@ -7117,7 +7096,7 @@
}
}
} catch (RuntimeException e) {
- Slog.e(TAG, "Unhandled exception while force removing for memory", e);
+ Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
}
try {
@@ -7152,7 +7131,7 @@
}
} catch (RuntimeException e) {
mInLayout = false;
- Slog.e(TAG, "Unhandled exception while layout out windows", e);
+ Log.wtf(TAG, "Unhandled exception while laying out windows", e);
}
}
@@ -8418,7 +8397,7 @@
}
}
} catch (RuntimeException e) {
- Slog.e(TAG, "Unhandled exception in Window Manager", e);
+ Log.wtf(TAG, "Unhandled exception in Window Manager", e);
}
Surface.closeTransaction();
@@ -9200,7 +9179,7 @@
if (windows == null || windows.contains(w)) {
pw.print(" Window #"); pw.print(i); pw.print(' ');
pw.print(w); pw.println(":");
- w.dump(pw, " ", dumpAll);
+ w.dump(pw, " ", dumpAll || windows != null);
}
}
if (mInputMethodDialogs.size() > 0) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0ff1cce..c9567d5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -22,6 +22,7 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <utils/Vector.h>
#include <hardware/hardware.h>
@@ -29,6 +30,7 @@
#include <EGL/egl.h>
+#include "LayerBase.h"
#include "HWComposer.h"
#include "SurfaceFlinger.h"
@@ -133,7 +135,8 @@
return mList ? mList->hwLayers : 0;
}
-void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const {
+void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
+ const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
if (mHwc && mList) {
result.append("Hardware Composer state:\n");
@@ -143,11 +146,12 @@
for (size_t i=0 ; i<mList->numHwLayers ; i++) {
const hwc_layer_t& l(mList->hwLayers[i]);
- snprintf(buffer, SIZE, " %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d]\n",
+ snprintf(buffer, SIZE, " %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
l.compositionType ? "OVERLAY" : "FB",
l.hints, l.flags, l.transform, l.blending,
l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
- l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom);
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ visibleLayersSortedByZ[i]->getName().string());
result.append(buffer);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 77c1a4b..8758a80 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -25,12 +25,14 @@
#include <hardware/hwcomposer.h>
#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
namespace android {
// ---------------------------------------------------------------------------
class String8;
class SurfaceFlinger;
+class LayerBase;
class HWComposer
{
@@ -63,7 +65,8 @@
hwc_layer_t* getLayers() const;
// for debugging
- void dump(String8& out, char* scratch, size_t SIZE) const;
+ void dump(String8& out, char* scratch, size_t SIZE,
+ const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
private:
struct cb_context {
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 603fb60..e5ce814 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -43,7 +43,7 @@
: dpy(display), contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger), mFiltering(false),
- mNeedsFiltering(false),
+ mNeedsFiltering(false), mInOverlay(false),
mOrientation(0),
mTransactionFlags(0),
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
@@ -344,6 +344,14 @@
hwcl->handle = NULL;
}
+void LayerBase::setOverlay(bool inOverlay) {
+ mInOverlay = inOverlay;
+}
+
+bool LayerBase::isOverlay() const {
+ return mInOverlay;
+}
+
void LayerBase::setFiltering(bool filtering)
{
mFiltering = filtering;
@@ -472,12 +480,13 @@
{
const Layer::State& s(drawingState());
snprintf(buffer, SIZE,
- "+ %s %p\n"
+ "+ %s %p (%s)\n"
" "
"z=%9d, pos=(%g,%g), size=(%4d,%4d), "
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- getTypeId(), this, s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
+ getTypeId(), this, getName().string(),
+ s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
isOpaque(), needsDithering(), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
@@ -553,9 +562,7 @@
sp<Client> client(mClientRef.promote());
snprintf(buffer, SIZE,
- " name=%s\n"
" client=%p, identity=%u\n",
- getName().string(),
client.get(), getIdentity());
result.append(buffer);
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index d20f06a..ee50428 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -109,8 +109,10 @@
virtual const char* getTypeId() const { return "LayerBase"; }
virtual void setGeometry(hwc_layer_t* hwcl);
-
virtual void setPerFrameData(hwc_layer_t* hwcl);
+ void setOverlay(bool inOverlay);
+ bool isOverlay() const;
+
/**
* draw - performs some global clipping optimizations
@@ -242,6 +244,11 @@
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
+ // this layer is currently handled by the hwc. this is
+ // updated at composition time, always frmo the composition
+ // thread.
+ bool mInOverlay;
+
protected:
// cached during validateVisibility()
int32_t mOrientation;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a3a8ea..df13640 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -817,20 +817,6 @@
mHwWorkListDirty = false;
HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
-
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- uint32_t flags = hw.getFlags();
- if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
- (flags & DisplayHardware::BUFFER_PRESERVED))
- {
- // we need to redraw everything (the whole screen)
- // NOTE: we could be more subtle here and redraw only
- // the area which will end-up in an overlay. But since this
- // shouldn't happen often, we invalidate everything.
- mDirtyRegion.set(hw.bounds());
- mInvalidRegion = mDirtyRegion;
- }
-
const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
const size_t count = currentLayers.size();
hwc.createWorkList(count);
@@ -890,30 +876,30 @@
}
}
- // compose all surfaces
+ Region expandDirty = setupHardwareComposer(mDirtyRegion);
+ mDirtyRegion.orSelf(expandDirty);
+ mInvalidRegion.orSelf(mDirtyRegion);
composeSurfaces(mDirtyRegion);
// clear the dirty regions
mDirtyRegion.clear();
}
-void SurfaceFlinger::composeSurfaces(const Region& dirty)
+Region SurfaceFlinger::setupHardwareComposer(const Region& dirty)
{
- if (UNLIKELY(!mWormholeRegion.isEmpty())) {
- // should never happen unless the window manager has a bug
- // draw something...
- drawWormhole();
- }
-
- status_t err = NO_ERROR;
- const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
- size_t count = layers.size();
+ Region dirtyOut(dirty);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
hwc_layer_t* const cur(hwc.getLayers());
+ if (!cur) {
+ return dirtyOut;
+ }
- LOGE_IF(cur && hwc.getNumLayers() != count,
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ size_t count = layers.size();
+
+ LOGE_IF(hwc.getNumLayers() != count,
"HAL number of layers (%d) doesn't match surfaceflinger (%d)",
hwc.getNumLayers(), count);
@@ -926,57 +912,95 @@
* update the per-frame h/w composer data for each layer
* and build the transparent region of the FB
*/
- Region transparent;
- if (cur) {
- for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(layers[i]);
- layer->setPerFrameData(&cur[i]);
- }
- err = hwc.prepare();
- LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->setPerFrameData(&cur[i]);
+ }
+ status_t err = hwc.prepare();
+ LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
- if (err == NO_ERROR) {
- for (size_t i=0 ; i<count ; i++) {
- if (cur[i].hints & HWC_HINT_CLEAR_FB) {
- const sp<LayerBase>& layer(layers[i]);
- if (layer->isOpaque()) {
- transparent.orSelf(layer->visibleRegionScreen);
- }
- }
+ if (err == NO_ERROR) {
+ Region transparent;
+ for (size_t i=0 ; i<count ; i++) {
+ // what's happening here is tricky.
+ // we want to clear all the layers with the CLEAR_FB flags
+ // that are opaque.
+ // however, since some GPU have are efficient at preserving
+ // the backbuffer, we want to take advantage of that so we do the
+ // clear only in the dirty region (other areas will be preserved
+ // on those GPUs).
+ // NOTE: on non backbuffer preserving GPU, the dirty region
+ // has already been expanded as needed, so the code is correct
+ // there too.
+ // However, the content of the framebuffer cannot be trusted when
+ // we switch to/from FB/OVERLAY, in which case we need to
+ // expand the dirty region to those areas too.
+ //
+ // Also we want to make sure to not clear areas that belong to
+ // layers above that won't redraw (we would just erasing them),
+ // that is, we can't erase anything outside the dirty region.
+
+ const sp<LayerBase>& layer(layers[i]);
+ if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) {
+ transparent.orSelf(layer->visibleRegionScreen);
}
- /*
- * clear the area of the FB that need to be transparent
- */
- transparent.andSelf(dirty);
- if (!transparent.isEmpty()) {
- glClearColor(0,0,0,0);
- Region::const_iterator it = transparent.begin();
- Region::const_iterator const end = transparent.end();
- const int32_t height = hw.getHeight();
- while (it != end) {
- const Rect& r(*it++);
- const GLint sy = height - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glClear(GL_COLOR_BUFFER_BIT);
- }
+ bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER) &&
+ !(cur[i].flags & HWC_SKIP_LAYER);
+
+ if (isOverlay != layer->isOverlay()) {
+ // we transitioned to/from overlay, so add this layer
+ // to the dirty region so the framebuffer can be either
+ // cleared or redrawn.
+ dirtyOut.orSelf(layer->visibleRegionScreen);
+ }
+ layer->setOverlay(isOverlay);
+ }
+
+
+ /*
+ * clear the area of the FB that need to be transparent
+ */
+ // don't erase stuff outside the dirty region
+ transparent.andSelf(dirtyOut);
+ if (!transparent.isEmpty()) {
+ glClearColor(0,0,0,0);
+ Region::const_iterator it = transparent.begin();
+ Region::const_iterator const end = transparent.end();
+ const int32_t height = hw.getHeight();
+ while (it != end) {
+ const Rect& r(*it++);
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glClear(GL_COLOR_BUFFER_BIT);
}
}
}
+ return dirtyOut;
+}
+void SurfaceFlinger::composeSurfaces(const Region& dirty)
+{
+ if (UNLIKELY(!mWormholeRegion.isEmpty())) {
+ // should never happen unless the window manager has a bug
+ // draw something...
+ drawWormhole();
+ }
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ HWComposer& hwc(hw.getHwComposer());
+ hwc_layer_t* const cur(hwc.getLayers());
/*
* and then, render the layers targeted at the framebuffer
*/
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- if (cur) {
- if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
+ if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER) &&
!(cur[i].flags & HWC_SKIP_LAYER)) {
- // skip layers handled by the HAL
- continue;
- }
+ continue;
}
-
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
if (!clip.isEmpty()) {
@@ -1597,7 +1621,7 @@
hwc.initCheck()==NO_ERROR ? "present" : "not present",
(mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
result.append(buffer);
- hwc.dump(result, buffer, SIZE);
+ hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
/*
* Dump gralloc state
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5f8eb08..126ca39 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -277,6 +277,7 @@
void handleWorkList();
void handleRepaint();
void postFramebuffer();
+ Region setupHardwareComposer(const Region& dirty);
void composeSurfaces(const Region& dirty);
void repaintEverything();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 54f3bb0..e7f1d9a 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -178,6 +178,7 @@
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -230,6 +231,7 @@
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -320,6 +322,7 @@
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -370,6 +373,7 @@
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -450,6 +454,7 @@
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -507,6 +512,7 @@
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -573,6 +579,7 @@
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
@@ -635,6 +642,7 @@
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index aa7568b..f769157 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -113,10 +113,15 @@
TelephonyManager telephony = TelephonyManager.getDefault();
LinkProperties linkProperties = null;
LinkCapabilities linkCapabilities = null;
+ boolean roaming = false;
+
if (state == Phone.DataState.CONNECTED) {
linkProperties = sender.getLinkProperties(apnType);
linkCapabilities = sender.getLinkCapabilities(apnType);
}
+ ServiceState ss = sender.getServiceState();
+ if (ss != null) roaming = ss.getRoaming();
+
try {
mRegistry.notifyDataConnection(
convertDataState(state),
@@ -126,7 +131,8 @@
linkProperties,
linkCapabilities,
((telephony!=null) ? telephony.getNetworkType() :
- TelephonyManager.NETWORK_TYPE_UNKNOWN));
+ TelephonyManager.NETWORK_TYPE_UNKNOWN),
+ roaming);
} catch (RemoteException ex) {
// system process is dead
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 3c83e50..1f19282 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -35,7 +35,7 @@
void notifyDataActivity(int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, in LinkProperties linkProperties,
- in LinkCapabilities linkCapabilities, int networkType);
+ in LinkCapabilities linkCapabilities, int networkType, boolean roaming);
void notifyDataConnectionFailed(String reason, String apnType);
void notifyCellLocation(in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 6347f37..5e64148 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -106,6 +106,7 @@
static final String DATA_IFACE_NAME_KEY = "iface";
static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
+ static final String DATA_NETWORK_ROAMING_KEY = "networkRoaming";
static final String PHONE_IN_ECM_STATE = "phoneinECMState";
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 1a077d0..a728d0a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -582,7 +582,12 @@
*/
@Override
protected void onRoamingOff() {
- trySetupData(Phone.REASON_ROAMING_OFF);
+ if (getDataOnRoamingEnabled() == false) {
+ notifyDataAvailability(Phone.REASON_ROAMING_OFF);
+ trySetupData(Phone.REASON_ROAMING_OFF);
+ } else {
+ notifyDataConnection(Phone.REASON_ROAMING_OFF);
+ }
}
/**
@@ -592,9 +597,11 @@
protected void onRoamingOn() {
if (getDataOnRoamingEnabled()) {
trySetupData(Phone.REASON_ROAMING_ON);
+ notifyDataConnection(Phone.REASON_ROAMING_ON);
} else {
if (DBG) log("Tear down data connection on roaming.");
cleanUpAllConnections(null);
+ notifyDataAvailability(Phone.REASON_ROAMING_ON);
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 00fb0e0..4e43fcd 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1681,23 +1681,25 @@
@Override
protected void onRoamingOff() {
if (DBG) log("onRoamingOff");
- // Notify data availability so APN can be enabled.
- notifyDataAvailability(Phone.REASON_ROAMING_OFF);
- setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
+ if (getDataOnRoamingEnabled() == false) {
+ notifyDataAvailability(Phone.REASON_ROAMING_OFF);
+ setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
+ } else {
+ notifyDataConnection(Phone.REASON_ROAMING_OFF);
+ }
}
@Override
protected void onRoamingOn() {
- // Notify data availability so APN can be enabled.
- notifyDataAvailability(Phone.REASON_ROAMING_ON);
-
if (getDataOnRoamingEnabled()) {
if (DBG) log("onRoamingOn: setup data on roaming");
setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
+ notifyDataConnection(Phone.REASON_ROAMING_ON);
} else {
if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
+ notifyDataAvailability(Phone.REASON_ROAMING_ON);
}
}
diff --git a/test-runner/src/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
index ff99a74..036a2275 100644
--- a/test-runner/src/android/test/InstrumentationCoreTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
@@ -51,35 +51,33 @@
/**
* Convenience definition of our log tag.
- */
+ */
private static final String TAG = "InstrumentationCoreTestRunner";
-
+
/**
* True if (and only if) we are running in single-test mode (as opposed to
* batch mode).
*/
private boolean singleTest = false;
-
+
@Override
public void onCreate(Bundle arguments) {
// We might want to move this to /sdcard, if is is mounted/writable.
File cacheDir = getTargetContext().getCacheDir();
- // Set some properties that the core tests absolutely need.
+ // Set some properties that the core tests absolutely need.
System.setProperty("user.language", "en");
System.setProperty("user.region", "US");
-
+
System.setProperty("java.home", cacheDir.getAbsolutePath());
System.setProperty("user.home", cacheDir.getAbsolutePath());
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
- System.setProperty("javax.net.ssl.trustStore",
- "/etc/security/cacerts.bks");
-
+
if (arguments != null) {
String classArg = arguments.getString(ARGUMENT_TEST_CLASS);
- singleTest = classArg != null && classArg.contains("#");
+ singleTest = classArg != null && classArg.contains("#");
}
-
+
super.onCreate(arguments);
}
@@ -89,36 +87,36 @@
runner.addTestListener(new TestListener() {
/**
- * The last test class we executed code from.
+ * The last test class we executed code from.
*/
private Class<?> lastClass;
-
+
/**
* The minimum time we expect a test to take.
*/
private static final int MINIMUM_TIME = 100;
-
+
/**
* The start time of our current test in System.currentTimeMillis().
*/
private long startTime;
-
+
public void startTest(Test test) {
if (test.getClass() != lastClass) {
lastClass = test.getClass();
printMemory(test.getClass());
}
-
+
Thread.currentThread().setContextClassLoader(
test.getClass().getClassLoader());
-
+
startTime = System.currentTimeMillis();
}
-
+
public void endTest(Test test) {
if (test instanceof TestCase) {
cleanup((TestCase)test);
-
+
/*
* Make sure all tests take at least MINIMUM_TIME to
* complete. If they don't, we wait a bit. The Cupcake
@@ -126,7 +124,7 @@
* short time, which causes headache for the CTS.
*/
long timeTaken = System.currentTimeMillis() - startTime;
-
+
if (timeTaken < MINIMUM_TIME) {
try {
Thread.sleep(MINIMUM_TIME - timeTaken);
@@ -136,15 +134,15 @@
}
}
}
-
+
public void addError(Test test, Throwable t) {
// This space intentionally left blank.
}
-
+
public void addFailure(Test test, AssertionFailedError t) {
// This space intentionally left blank.
}
-
+
/**
* Dumps some memory info.
*/
@@ -154,7 +152,7 @@
long total = runtime.totalMemory();
long free = runtime.freeMemory();
long used = total - free;
-
+
Log.d(TAG, "Total memory : " + total);
Log.d(TAG, "Used memory : " + used);
Log.d(TAG, "Free memory : " + free);
@@ -170,7 +168,7 @@
*/
private void cleanup(TestCase test) {
Class<?> clazz = test.getClass();
-
+
while (clazz != TestCase.class) {
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
@@ -185,15 +183,15 @@
}
}
}
-
+
clazz = clazz.getSuperclass();
}
}
-
+
});
-
+
return runner;
- }
+ }
@Override
List<Predicate<TestMethod>> getBuilderRequirements() {
diff --git a/tests/RenderScriptTests/ImageProcessing/Android.mk b/tests/RenderScriptTests/ImageProcessing/Android.mk
index 507cc92..d7486e8 100644
--- a/tests/RenderScriptTests/ImageProcessing/Android.mk
+++ b/tests/RenderScriptTests/ImageProcessing/Android.mk
@@ -17,7 +17,9 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-renderscript-files-under, src)
diff --git a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
index 174cc65..2232b98 100644
--- a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
+++ b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
@@ -2,10 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.rs.image">
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk android:minSdkVersion="11" />
<application android:label="Image Processing"
android:hardwareAccelerated="true">
+ <uses-library android:name="android.test.runner" />
<activity android:name="ImageProcessingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -13,4 +14,9 @@
</intent-filter>
</activity>
</application>
+
+ <instrumentation android:name=".ImageProcessingTestRunner"
+ android:targetPackage="com.android.rs.image"
+ android:label="Test runner for Image Processing Benchmark Test"
+ />
</manifest>
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 9aa70b0..3615f60 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -33,11 +33,13 @@
import android.widget.SeekBar;
import android.widget.TextView;
import android.view.View;
+import android.util.Log;
import java.lang.Math;
public class ImageProcessingActivity extends Activity
implements SurfaceHolder.Callback,
SeekBar.OnSeekBarChangeListener {
+ private final String TAG = "Img";
private Bitmap mBitmapIn;
private Bitmap mBitmapOut;
private ScriptC_threshold mScript;
@@ -268,7 +270,15 @@
// button hook
public void benchmark(View v) {
- android.util.Log.v("Img", "Benchmarking");
+ long t = getBenchmark();
+ //long javaTime = javaFilter();
+ //mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms");
+ mBenchmarkResult.setText("Result: " + t + " ms");
+ }
+
+ // For benchmark test
+ public long getBenchmark() {
+ Log.v(TAG, "Benchmarking");
int oldRadius = mRadius;
mRadius = MAX_RADIUS;
mScript.set_radius(mRadius);
@@ -279,16 +289,12 @@
mOutPixelsAllocation.copyTo(mBitmapOut);
t = java.lang.System.currentTimeMillis() - t;
- android.util.Log.v("Img", "Renderscript frame time core ms " + t);
-
- //long javaTime = javaFilter();
- //mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms");
- mBenchmarkResult.setText("Result: " + t + " ms");
-
+ Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
mRadius = oldRadius;
mScript.set_radius(mRadius);
mScript.invoke_filter();
mOutPixelsAllocation.copyTo(mBitmapOut);
+ return t;
}
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
new file mode 100644
index 0000000..d2298da
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.rs.image;
+
+import android.os.Bundle;
+import android.os.Environment;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * ImageProcessing benchmark test.
+ * To run the test, please use command
+ *
+ * adb shell am instrument -w com.android.rs.image/.ImageProcessingTestRunner
+ *
+ */
+public class ImageProcessingTest extends ActivityInstrumentationTestCase2<ImageProcessingActivity> {
+ private final String TAG = "ImageProcessingTest";
+ private final String RESULT_FILE = "image_processing_result.txt";
+ private ImageProcessingActivity mAct;
+
+ public ImageProcessingTest() {
+ super(ImageProcessingActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mAct = getActivity();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * ImageProcessing benchmark test
+ */
+ @LargeTest
+ public void testImageProcessingBench() {
+ long t = mAct.getBenchmark();
+ Log.v(TAG, "t = " + t);
+
+ // write result into a file
+ File externalStorage = Environment.getExternalStorageDirectory();
+ if (!externalStorage.canWrite()) {
+ Log.v(TAG, "sdcard is not writable");
+ return;
+ }
+ File resultFile = new File(externalStorage, RESULT_FILE);
+ resultFile.setWritable(true, false);
+ try {
+ BufferedWriter results = new BufferedWriter(new FileWriter(resultFile));
+ results.write("Renderscript frame time core: " + t + " ms");
+ results.close();
+ Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
+ } catch (IOException e) {
+ Log.v(TAG, "Unable to write result file " + e.getMessage());
+ }
+ }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java
new file mode 100644
index 0000000..4e27b7f
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image;
+
+import com.android.rs.image.ImageProcessingTest;
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import junit.framework.TestSuite;
+
+/**
+ * Run the ImageProcessing benchmark test
+ * adb shell am instrument -w com.android.rs.image/.ImageProcessingTestRunner
+ *
+ */
+public class ImageProcessingTestRunner extends InstrumentationTestRunner {
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(ImageProcessingTest.class);
+ return suite;
+ }
+}
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
index 84c7166..e2d820e 100644
--- a/voip/jni/rtp/AmrCodec.cpp
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -52,7 +52,7 @@
int set(int sampleRate, const char *fmtp);
int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
+ int decode(int16_t *samples, int count, void *payload, int length);
private:
void *mEncoder;
@@ -128,7 +128,7 @@
return length;
}
-int AmrCodec::decode(int16_t *samples, void *payload, int length)
+int AmrCodec::decode(int16_t *samples, int count, void *payload, int length)
{
unsigned char *bytes = (unsigned char *)payload;
Frame_Type_3GPP type;
@@ -213,7 +213,7 @@
}
int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
+ int decode(int16_t *samples, int count, void *payload, int length);
private:
void *mEncoder;
@@ -239,20 +239,24 @@
return -1;
}
-int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
+int GsmEfrCodec::decode(int16_t *samples, int count, void *payload, int length)
{
unsigned char *bytes = (unsigned char *)payload;
- if (length == 31 && (bytes[0] >> 4) == 0x0C) {
+ int n = 0;
+ while (n + 160 <= count && length >= 31 && (bytes[0] >> 4) == 0x0C) {
for (int i = 0; i < 30; ++i) {
bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
}
bytes[30] <<= 4;
- if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
- return 160;
+ if (AMRDecode(mDecoder, AMR_122, bytes, &samples[n], MIME_IETF) != 31) {
+ break;
}
+ n += 160;
+ length -= 31;
+ bytes += 31;
}
- return -1;
+ return n;
}
} // namespace
diff --git a/voip/jni/rtp/AudioCodec.h b/voip/jni/rtp/AudioCodec.h
index e389255..741730b 100644
--- a/voip/jni/rtp/AudioCodec.h
+++ b/voip/jni/rtp/AudioCodec.h
@@ -30,7 +30,7 @@
// Returns the length of payload in bytes.
virtual int encode(void *payload, int16_t *samples) = 0;
// Returns the number of decoded samples.
- virtual int decode(int16_t *samples, void *payload, int length) = 0;
+ virtual int decode(int16_t *samples, int count, void *payload, int length) = 0;
};
AudioCodec *newAudioCodec(const char *codecName);
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 5f07bb5..93c809e 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -395,7 +395,8 @@
mLatencyTimer = tick;
}
- if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
+ int count = (BUFFER_SIZE - (mBufferTail - mBufferHead)) * mSampleRate;
+ if (count < mSampleCount) {
// Buffer overflow. Drop the packet.
LOGV("stream[%d] buffer overflow", mSocket);
recv(mSocket, &c, 1, MSG_DONTWAIT);
@@ -403,19 +404,18 @@
}
// Receive the packet and decode it.
- int16_t samples[mSampleCount];
- int length = 0;
+ int16_t samples[count];
if (!mCodec) {
// Special case for device stream.
- length = recv(mSocket, samples, sizeof(samples),
+ count = recv(mSocket, samples, sizeof(samples),
MSG_TRUNC | MSG_DONTWAIT) >> 1;
} else {
__attribute__((aligned(4))) uint8_t buffer[2048];
sockaddr_storage remote;
- socklen_t len = sizeof(remote);
+ socklen_t addrlen = sizeof(remote);
- length = recvfrom(mSocket, buffer, sizeof(buffer),
- MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
+ int length = recvfrom(mSocket, buffer, sizeof(buffer),
+ MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &addrlen);
// Do we need to check SSRC, sequence, and timestamp? They are not
// reliable but at least they can be used to identify duplicates?
@@ -433,14 +433,15 @@
}
length -= offset;
if (length >= 0) {
- length = mCodec->decode(samples, &buffer[offset], length);
+ length = mCodec->decode(samples, count, &buffer[offset], length);
}
if (length > 0 && mFixRemote) {
mRemote = remote;
mFixRemote = false;
}
+ count = length;
}
- if (length <= 0) {
+ if (count <= 0) {
LOGV("stream[%d] decoder error", mSocket);
return;
}
@@ -462,7 +463,7 @@
// Append to the jitter buffer.
int tail = mBufferTail * mSampleRate;
- for (int i = 0; i < mSampleCount; ++i) {
+ for (int i = 0; i < count; ++i) {
mBuffer[tail & mBufferMask] = samples[i];
++tail;
}
diff --git a/voip/jni/rtp/G711Codec.cpp b/voip/jni/rtp/G711Codec.cpp
index a467acf..ef54863 100644
--- a/voip/jni/rtp/G711Codec.cpp
+++ b/voip/jni/rtp/G711Codec.cpp
@@ -39,7 +39,7 @@
return mSampleCount;
}
int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
+ int decode(int16_t *samples, int count, void *payload, int length);
private:
int mSampleCount;
};
@@ -64,9 +64,12 @@
return mSampleCount;
}
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
+int UlawCodec::decode(int16_t *samples, int count, void *payload, int length)
{
int8_t *ulaws = (int8_t *)payload;
+ if (length > count) {
+ length = count;
+ }
for (int i = 0; i < length; ++i) {
int ulaw = ~ulaws[i];
int exponent = (ulaw >> 4) & 0x07;
@@ -87,7 +90,7 @@
return mSampleCount;
}
int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
+ int decode(int16_t *samples, int count, void *payload, int length);
private:
int mSampleCount;
};
@@ -111,9 +114,12 @@
return mSampleCount;
}
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
+int AlawCodec::decode(int16_t *samples, int count, void *payload, int length)
{
int8_t *alaws = (int8_t *)payload;
+ if (length > count) {
+ length = count;
+ }
for (int i = 0; i < length; ++i) {
int alaw = alaws[i] ^ 0x55;
int exponent = (alaw >> 4) & 0x07;
diff --git a/voip/jni/rtp/GsmCodec.cpp b/voip/jni/rtp/GsmCodec.cpp
index 8d2286e..61dfdc9 100644
--- a/voip/jni/rtp/GsmCodec.cpp
+++ b/voip/jni/rtp/GsmCodec.cpp
@@ -44,7 +44,7 @@
}
int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
+ int decode(int16_t *samples, int count, void *payload, int length);
private:
gsm mEncode;
@@ -57,13 +57,17 @@
return 33;
}
-int GsmCodec::decode(int16_t *samples, void *payload, int length)
+int GsmCodec::decode(int16_t *samples, int count, void *payload, int length)
{
- if (length == 33 &&
- gsm_decode(mDecode, (unsigned char *)payload, samples) == 0) {
- return 160;
+ unsigned char *bytes = (unsigned char *)payload;
+ int n = 0;
+ while (n + 160 <= count && length >= 33 &&
+ gsm_decode(mDecode, bytes, &samples[n]) == 0) {
+ n += 160;
+ length -= 33;
+ bytes += 33;
}
- return -1;
+ return n;
}
} // namespace
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0757efd..27a60cd 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -18,7 +18,7 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WpsConfiguration;
+import android.net.wifi.Wps;
import android.net.wifi.WpsResult;
import android.net.wifi.ScanResult;
import android.net.DhcpInfo;
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 83dda5c..c75dec7 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -397,7 +397,7 @@
* Start WPS pin method configuration with pin obtained
* from the access point
*/
- static WpsResult startWpsWithPinFromAccessPoint(WpsConfiguration config) {
+ static WpsResult startWpsWithPinFromAccessPoint(Wps config) {
WpsResult result = new WpsResult();
if (WifiNative.startWpsWithPinFromAccessPointCommand(config.BSSID, config.pin)) {
/* WPS leaves all networks disabled */
@@ -415,7 +415,7 @@
* from the device
* @return WpsResult indicating status and pin
*/
- static WpsResult startWpsWithPinFromDevice(WpsConfiguration config) {
+ static WpsResult startWpsWithPinFromDevice(Wps config) {
WpsResult result = new WpsResult();
result.pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID);
/* WPS leaves all networks disabled */
@@ -432,7 +432,7 @@
/**
* Start WPS push button configuration
*/
- static WpsResult startWpsPbc(WpsConfiguration config) {
+ static WpsResult startWpsPbc(Wps config) {
WpsResult result = new WpsResult();
if (WifiNative.startWpsPbcCommand(config.BSSID)) {
/* WPS leaves all networks disabled */
@@ -594,7 +594,7 @@
sendConfiguredNetworksChangedBroadcast();
}
- static void updateIpAndProxyFromWpsConfig(int netId, WpsConfiguration wpsConfig) {
+ static void updateIpAndProxyFromWpsConfig(int netId, Wps wpsConfig) {
synchronized (sConfiguredNetworks) {
WifiConfiguration config = sConfiguredNetworks.get(netId);
if (config != null) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5f8385c..0fce8e8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1175,7 +1175,7 @@
* @param config WPS configuration
* @hide
*/
- public void startWps(WpsConfiguration config) {
+ public void startWps(Wps config) {
if (config == null) {
return;
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index cebcc47..6cc09e9 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -261,10 +261,10 @@
public static String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
if (config == null) return null;
List<String> args = new ArrayList<String>();
- WpsConfiguration wpsConfig = config.wpsConfig;
+ Wps wps = config.wps;
args.add(config.deviceAddress);
- switch (wpsConfig.setup) {
+ switch (wps.setup) {
case PBC:
args.add("pbc");
break;
@@ -274,11 +274,11 @@
args.add("display");
break;
case KEYPAD:
- args.add(wpsConfig.pin);
+ args.add(wps.pin);
args.add("keypad");
break;
case LABEL:
- args.add(wpsConfig.pin);
+ args.add(wps.pin);
args.add("label");
default:
break;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index d116e5b..175a9ce 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -880,7 +880,7 @@
sendMessage(message);
}
- public void startWps(Messenger replyTo, WpsConfiguration config) {
+ public void startWps(Messenger replyTo, Wps config) {
Message msg = obtainMessage(CMD_START_WPS, config);
msg.replyTo = replyTo;
sendMessage(msg);
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index c52142d..fe0e850 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -77,15 +77,15 @@
/**
* Low signal is defined as less than or equal to cut off
*/
- private static final int LOW_SIGNAL_CUTOFF = 1;
+ private static final int LOW_SIGNAL_CUTOFF = 0;
private static final long DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS = 2 * 60 * 1000;
- private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 30 * 60 * 1000;
+ private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 60 * 60 * 1000;
private static final long DEFAULT_WALLED_GARDEN_INTERVAL_MS = 30 * 60 * 1000;
private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
- private static final int DEFAULT_NUM_DNS_PINGS = 15; // Multiple pings to detect setup issues
- private static final int DEFAULT_MIN_DNS_RESPONSES = 3;
+ private static final int DEFAULT_NUM_DNS_PINGS = 5; // Multiple pings to detect setup issues
+ private static final int DEFAULT_MIN_DNS_RESPONSES = 1;
private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 2000;
@@ -95,7 +95,9 @@
private static final String DEFAULT_WALLED_GARDEN_URL =
"http://clients3.google.com/generate_204";
private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
- private static final int DNS_INTRATEST_PING_INTERVAL = 200; // Long delay to detect setup issues
+ private static final int DNS_INTRATEST_PING_INTERVAL_MS = 200;
+ /* With some router setups, it takes a few hunder milli-seconds before connection is active */
+ private static final int DNS_START_DELAY_MS = 1000;
private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
@@ -677,7 +679,7 @@
for (int i=0; i < mNumDnsPings; i++) {
for (int j = 0; j < numDnses; j++) {
idDnsMap.put(mDnsPinger.pingDnsAsync(mDnsList.get(j), mDnsPingTimeoutMs,
- DNS_INTRATEST_PING_INTERVAL * i), j);
+ DNS_START_DELAY_MS + DNS_INTRATEST_PING_INTERVAL_MS * i), j);
}
}
}
diff --git a/wifi/java/android/net/wifi/WpsConfiguration.aidl b/wifi/java/android/net/wifi/Wps.aidl
similarity index 95%
rename from wifi/java/android/net/wifi/WpsConfiguration.aidl
rename to wifi/java/android/net/wifi/Wps.aidl
index 6c26833..ba82a9a 100644
--- a/wifi/java/android/net/wifi/WpsConfiguration.aidl
+++ b/wifi/java/android/net/wifi/Wps.aidl
@@ -16,4 +16,4 @@
package android.net.wifi;
-parcelable WpsConfiguration;
+parcelable Wps;
diff --git a/wifi/java/android/net/wifi/WpsConfiguration.java b/wifi/java/android/net/wifi/Wps.java
similarity index 85%
rename from wifi/java/android/net/wifi/WpsConfiguration.java
rename to wifi/java/android/net/wifi/Wps.java
index 0c2adfd..6d006960 100644
--- a/wifi/java/android/net/wifi/WpsConfiguration.java
+++ b/wifi/java/android/net/wifi/Wps.java
@@ -25,12 +25,14 @@
import java.util.BitSet;
/**
- * A class representing a WPS network configuration
+ * A class representing Wi-Fi Protected Setup
* @hide
+ *
+ * {@see WifiP2pConfig}
*/
-public class WpsConfiguration implements Parcelable {
+public class Wps implements Parcelable {
- /* Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
+ /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
public enum Setup {
/* Push button configuration */
PBC,
@@ -49,6 +51,7 @@
/** @hide */
public String BSSID;
+ /** Passed with pin method configuration */
public String pin;
/** @hide */
@@ -60,8 +63,7 @@
/** @hide */
public LinkProperties linkProperties;
- /** @hide */
- public WpsConfiguration() {
+ public Wps() {
setup = Setup.INVALID;
BSSID = null;
pin = null;
@@ -94,7 +96,7 @@
}
/** copy constructor {@hide} */
- public WpsConfiguration(WpsConfiguration source) {
+ public Wps(Wps source) {
if (source != null) {
setup = source.setup;
BSSID = source.BSSID;
@@ -116,10 +118,10 @@
}
/** Implement the Parcelable interface {@hide} */
- public static final Creator<WpsConfiguration> CREATOR =
- new Creator<WpsConfiguration>() {
- public WpsConfiguration createFromParcel(Parcel in) {
- WpsConfiguration config = new WpsConfiguration();
+ public static final Creator<Wps> CREATOR =
+ new Creator<Wps>() {
+ public Wps createFromParcel(Parcel in) {
+ Wps config = new Wps();
config.setup = Setup.valueOf(in.readString());
config.BSSID = in.readString();
config.pin = in.readString();
@@ -129,8 +131,8 @@
return config;
}
- public WpsConfiguration[] newArray(int size) {
- return new WpsConfiguration[size];
+ public Wps[] newArray(int size) {
+ return new Wps[size];
}
};
}
diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java
index af089ab..f9e903a 100644
--- a/wifi/java/android/net/wifi/WpsStateMachine.java
+++ b/wifi/java/android/net/wifi/WpsStateMachine.java
@@ -53,7 +53,7 @@
private WifiStateMachine mWifiStateMachine;
- private WpsConfiguration mWpsConfig;
+ private Wps mWpsConfig;
private Context mContext;
AsyncChannel mReplyChannel = new AsyncChannel();
@@ -90,10 +90,10 @@
@Override
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- WpsConfiguration wpsConfig;
+ Wps wpsConfig;
switch (message.what) {
case WifiStateMachine.CMD_START_WPS:
- mWpsConfig = (WpsConfiguration) message.obj;
+ mWpsConfig = (Wps) message.obj;
WpsResult result;
switch (mWpsConfig.setup) {
case PBC:
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index a0c7dd1..381a450 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -26,6 +26,5 @@
interface IWifiP2pManager
{
Messenger getMessenger();
- boolean isP2pSupported();
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 686d698..e359ce5 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -16,26 +16,28 @@
package android.net.wifi.p2p;
-import android.net.wifi.WpsConfiguration;
-import android.net.wifi.WpsConfiguration.Setup;
+import android.net.wifi.Wps;
+import android.net.wifi.Wps.Setup;
import android.os.Parcelable;
import android.os.Parcel;
/**
- * A class representing a Wi-Fi P2p configuration
+ * A class representing a Wi-Fi P2p configuration for setting up a connection
* @hide
+ *
+ * {@see WifiP2pManager}
*/
public class WifiP2pConfig implements Parcelable {
/**
- * Device address
+ * The device MAC address uniquely identifies a Wi-Fi p2p device
*/
public String deviceAddress;
/**
- * WPS configuration
+ * Wi-Fi Protected Setup information
*/
- public WpsConfiguration wpsConfig;
+ public Wps wps;
/**
* This is an integer value between 0 and 15 where 0 indicates the least
@@ -61,11 +63,11 @@
public WifiP2pConfig() {
//set defaults
- wpsConfig = new WpsConfiguration();
- wpsConfig.setup = Setup.PBC;
+ wps = new Wps();
+ wps.setup = Setup.PBC;
}
- /* P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 */
+ /** P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 {@hide}*/
public WifiP2pConfig(String supplicantEvent) throws IllegalArgumentException {
String[] tokens = supplicantEvent.split(" ");
@@ -74,7 +76,7 @@
}
deviceAddress = tokens[1];
- wpsConfig = new WpsConfiguration();
+ wps = new Wps();
if (tokens.length > 2) {
String[] nameVal = tokens[2].split("=");
@@ -87,28 +89,29 @@
//As defined in wps/wps_defs.h
switch (devPasswdId) {
case 0x00:
- wpsConfig.setup = Setup.LABEL;
+ wps.setup = Setup.LABEL;
break;
case 0x01:
- wpsConfig.setup = Setup.KEYPAD;
+ wps.setup = Setup.KEYPAD;
break;
case 0x04:
- wpsConfig.setup = Setup.PBC;
+ wps.setup = Setup.PBC;
break;
case 0x05:
- wpsConfig.setup = Setup.DISPLAY;
+ wps.setup = Setup.DISPLAY;
break;
default:
- wpsConfig.setup = Setup.PBC;
+ wps.setup = Setup.PBC;
break;
}
}
}
+ /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("\n address: ").append(deviceAddress);
- sbuf.append("\n wps: ").append(wpsConfig);
+ sbuf.append("\n wps: ").append(wps);
sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent);
sbuf.append("\n persist: ").append(persist.toString());
return sbuf.toString();
@@ -129,7 +132,7 @@
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(deviceAddress);
- dest.writeParcelable(wpsConfig, flags);
+ dest.writeParcelable(wps, flags);
dest.writeInt(groupOwnerIntent);
dest.writeString(persist.name());
}
@@ -140,7 +143,7 @@
public WifiP2pConfig createFromParcel(Parcel in) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = in.readString();
- config.wpsConfig = (WpsConfiguration) in.readParcelable(null);
+ config.wps = (Wps) in.readParcelable(null);
config.groupOwnerIntent = in.readInt();
config.persist = Persist.valueOf(in.readString());
return config;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 7908726..99c585f 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -25,17 +25,20 @@
/**
* A class representing a Wi-Fi p2p device
* @hide
+ *
+ * {@see WifiP2pManager}
*/
public class WifiP2pDevice implements Parcelable {
private static final String TAG = "WifiP2pDevice";
+
/**
- * Device name
+ * The device name is a user friendly string to identify a Wi-Fi p2p device
*/
public String deviceName;
/**
- * Device MAC address
+ * The device MAC address uniquely identifies a Wi-Fi p2p device
*/
public String deviceAddress;
@@ -46,35 +49,30 @@
* P2P Interface Address and the group interface will be created with
* address as the local address in case of successfully completed
* negotiation.
+ * @hide
*/
public String interfaceAddress;
/**
- * Primary device type
+ * Primary device type identifies the type of device. For example, an application
+ * could filter the devices discovered to only display printers if the purpose is to
+ * enable a printing action from the user. See the Wi-Fi Direct technical specification
+ * for the full list of standard device types supported.
*/
public String primaryDeviceType;
/**
- * Secondary device type
+ * Secondary device type is an optional attribute that can be provided by a device in
+ * addition to the primary device type.
*/
public String secondaryDeviceType;
// These definitions match the ones in wpa_supplicant
/* WPS config methods supported */
- private static final int WPS_CONFIG_USBA = 0x0001;
- private static final int WPS_CONFIG_ETHERNET = 0x0002;
- private static final int WPS_CONFIG_LABEL = 0x0004;
private static final int WPS_CONFIG_DISPLAY = 0x0008;
- private static final int WPS_CONFIG_EXT_NFC_TOKEN = 0x0010;
- private static final int WPS_CONFIG_INT_NFC_TOKEN = 0x0020;
- private static final int WPS_CONFIG_NFC_INTERFACE = 0x0040;
private static final int WPS_CONFIG_PUSHBUTTON = 0x0080;
private static final int WPS_CONFIG_KEYPAD = 0x0100;
- private static final int WPS_CONFIG_VIRT_PUSHBUTTON = 0x0280;
- private static final int WPS_CONFIG_PHY_PUSHBUTTON = 0x0480;
- private static final int WPS_CONFIG_VIRT_DISPLAY = 0x2008;
- private static final int WPS_CONFIG_PHY_DISPLAY = 0x4008;
/* Device Capability bitmap */
private static final int DEVICE_CAPAB_SERVICE_DISCOVERY = 1;
@@ -95,19 +93,23 @@
/**
* WPS config methods supported
+ * @hide
*/
public int wpsConfigMethodsSupported;
/**
* Device capability
+ * @hide
*/
public int deviceCapability;
/**
* Group capability
+ * @hide
*/
public int groupCapability;
+ /** Device connection status */
public enum Status {
CONNECTED,
INVITED,
@@ -118,7 +120,7 @@
public Status status = Status.UNAVAILABLE;
- public WifiP2pDevice() {
+ WifiP2pDevice() {
}
/**
@@ -144,6 +146,7 @@
* group_capab=0x0
*
* Note: The events formats can be looked up in the wpa_supplicant code
+ * @hide
*/
public WifiP2pDevice(String string) throws IllegalArgumentException {
String[] tokens = string.split(" ");
@@ -198,11 +201,33 @@
}
}
+ /** Returns true if WPS push button configuration is supported */
+ public boolean wpsPbcSupported() {
+ return (wpsConfigMethodsSupported & WPS_CONFIG_PUSHBUTTON) != 0;
+ }
+
+ /** Returns true if WPS keypad configuration is supported */
+ public boolean wpsKeypadSupported() {
+ return (wpsConfigMethodsSupported & WPS_CONFIG_KEYPAD) != 0;
+ }
+
+ /** Returns true if WPS display configuration is supported */
+ public boolean wpsDisplaySupported() {
+ return (wpsConfigMethodsSupported & WPS_CONFIG_DISPLAY) != 0;
+ }
+
+ /** Returns true if the device is capable of service discovery */
+ public boolean isServiceDiscoveryCapable() {
+ return (deviceCapability & DEVICE_CAPAB_SERVICE_DISCOVERY) != 0;
+ }
+
+ /** Returns true if the device is a group owner */
public boolean isGroupOwner() {
return (groupCapability & GROUP_CAPAB_GROUP_OWNER) != 0;
}
@Override
+ /** @hide */
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof WifiP2pDevice)) return false;
@@ -214,6 +239,7 @@
return other.deviceAddress.equals(deviceAddress);
}
+ /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("Device: ").append(deviceName);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index aa3554c..242bce0 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -28,22 +28,25 @@
/**
* A class representing a Wi-Fi P2p device list
* @hide
+ *
+ * {@see WifiP2pManager}
*/
public class WifiP2pDeviceList implements Parcelable {
private Collection<WifiP2pDevice> mDevices;
- public WifiP2pDeviceList() {
+ WifiP2pDeviceList() {
mDevices = new ArrayList<WifiP2pDevice>();
}
- //copy constructor
+ /** copy constructor {@hide} */
public WifiP2pDeviceList(WifiP2pDeviceList source) {
if (source != null) {
mDevices = source.getDeviceList();
}
}
+ /** @hide */
public WifiP2pDeviceList(ArrayList<WifiP2pDevice> devices) {
mDevices = new ArrayList<WifiP2pDevice>();
for (WifiP2pDevice device : devices) {
@@ -51,12 +54,14 @@
}
}
+ /** @hide */
public boolean clear() {
if (mDevices.isEmpty()) return false;
mDevices.clear();
return true;
}
+ /** @hide */
public void update(WifiP2pDevice device) {
if (device == null) return;
for (WifiP2pDevice d : mDevices) {
@@ -75,15 +80,18 @@
mDevices.add(device);
}
+ /** @hide */
public boolean remove(WifiP2pDevice device) {
if (device == null) return false;
return mDevices.remove(device);
}
+ /** Get the list of devices */
public Collection<WifiP2pDevice> getDeviceList() {
return Collections.unmodifiableCollection(mDevices);
}
+ /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
for (WifiP2pDevice device : mDevices) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index e35d360..48f210b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -27,6 +27,8 @@
/**
* A class representing a Wi-Fi P2p group
* @hide
+ *
+ * {@see WifiP2pManager}
*/
public class WifiP2pGroup implements Parcelable {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index a02175e..81b7708 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -23,15 +23,20 @@
import java.net.UnknownHostException;
/**
- * A class representing connection info on Wi-fi P2p
+ * A class representing connection information about a Wi-Fi p2p group
* @hide
+ *
+ * {@see WifiP2pManager}
*/
public class WifiP2pInfo implements Parcelable {
+ /** Indicates if a p2p group has been successfully formed */
public boolean groupFormed;
+ /** Indicates if the current device is the group owner */
public boolean isGroupOwner;
+ /** Group owner address */
public InetAddress groupOwnerAddress;
/** @hide */
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 11de9c4..5715186 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -64,7 +64,7 @@
* use {@link #requestConnectionInfo} to fetch the connection details. Connection information
* can be obtained with {@link #connectionInfoInResponse} on a {@link #RESPONSE_CONNECTION_INFO}
* message. The connection info {@link WifiP2pInfo} contains the address of the group owner
- * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link #WifiP2pInfo#isGroupOwner} to indicate
+ * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
* if the current device is a p2p group owner. A p2p client can thus communicate with
* the p2p group owner through a socket connection.
*
@@ -85,6 +85,7 @@
* {@see WifiP2pGroup}
* {@see WifiP2pDevice}
* {@see WifiP2pDeviceList}
+ * {@see android.net.wifi.Wps}
* @hide
*/
public class WifiP2pManager {
@@ -399,15 +400,6 @@
}
}
- /** @hide */
- public boolean isP2pSupported() {
- try {
- return mService.isP2pSupported();
- } catch (RemoteException e) {
- return false;
- }
- }
-
/**
* Sends in a request to the system to enable p2p. This will pop up a dialog
* to the user and upon authorization will enable p2p.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 5297302..2f7b927 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -41,8 +41,8 @@
import android.net.wifi.WifiMonitor;
import android.net.wifi.WifiNative;
import android.net.wifi.WifiStateMachine;
-import android.net.wifi.WpsConfiguration;
-import android.net.wifi.WpsConfiguration.Setup;
+import android.net.wifi.Wps;
+import android.net.wifi.Wps.Setup;
import android.net.wifi.p2p.WifiP2pDevice.Status;
import android.os.Binder;
import android.os.IBinder;
@@ -128,7 +128,12 @@
public static final int GROUP_NEGOTIATION_TIMED_OUT = BASE + 3;
/* User accepted to disable Wi-Fi in order to enable p2p */
- private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 11;
+ private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 4;
+ /* User rejected to disable Wi-Fi in order to enable p2p */
+ private static final int WIFI_DISABLE_USER_REJECT = BASE + 5;
+
+ /* Airplane mode changed */
+ private static final int AIRPLANE_MODE_CHANGED = BASE + 6;
private final boolean mP2pSupported;
private final String mDeviceType;
@@ -153,8 +158,9 @@
mInterface = SystemProperties.get("wifi.interface", "wlan0");
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
- mP2pSupported = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_wifi_p2p_support);
+ mP2pSupported = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_DIRECT);
+
mDeviceType = mContext.getResources().getString(
com.android.internal.R.string.config_wifi_p2p_device_type);
mDeviceName = getDefaultDeviceName();
@@ -165,6 +171,7 @@
// broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mContext.registerReceiver(new WifiStateReceiver(), filter);
@@ -184,6 +191,8 @@
} else if (intent.getAction().equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
WifiManager.WIFI_AP_STATE_DISABLED);
+ } else if (intent.getAction().equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+ mP2pStateMachine.sendMessage(AIRPLANE_MODE_CHANGED);
}
}
}
@@ -216,14 +225,6 @@
return new Messenger(mP2pStateMachine.getHandler());
}
- /**
- * Return if p2p is supported
- */
- public boolean isP2pSupported() {
- enforceAccessPermission();
- return mP2pSupported;
- }
-
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -357,8 +358,12 @@
case WifiP2pManager.REQUEST_GROUP_INFO:
replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
break;
- // Ignore
+ case AIRPLANE_MODE_CHANGED:
+ if (isAirplaneModeOn()) sendMessage(WifiP2pManager.DISABLE_P2P);
+ break;
+ // Ignore
case WIFI_DISABLE_USER_ACCEPT:
+ case WIFI_DISABLE_USER_REJECT:
case GROUP_NEGOTIATION_TIMED_OUT:
break;
default:
@@ -457,8 +462,7 @@
if (which == DialogInterface.BUTTON_POSITIVE) {
sendMessage(WIFI_DISABLE_USER_ACCEPT);
} else {
- logd("User rejected enabling p2p");
- //ignore
+ sendMessage(WIFI_DISABLE_USER_REJECT);
}
}
};
@@ -509,6 +513,11 @@
mWifiChannel.sendMessage(P2P_ENABLE_PENDING);
transitionTo(mWaitForWifiDisableState);
break;
+ case WIFI_DISABLE_USER_REJECT:
+ logd("User rejected enabling p2p");
+ sendP2pStateChangedBroadcast(false);
+ transitionTo(mP2pDisabledState);
+ break;
case WifiP2pManager.ENABLE_P2P:
case WifiP2pManager.DISABLE_P2P:
deferMessage(message);
@@ -1027,7 +1036,7 @@
private void notifyP2pGoNegotationRequest(WifiP2pConfig config) {
Resources r = Resources.getSystem();
- WpsConfiguration wpsConfig = config.wpsConfig;
+ Wps wps = config.wps;
final View textEntryView = LayoutInflater.from(mContext)
.inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null);
final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin);
@@ -1040,10 +1049,10 @@
if (DBG) logd(getName() + " connect " + pin.getText());
if (pin.getVisibility() == View.GONE) {
- mSavedGoNegotiationConfig.wpsConfig.setup = Setup.PBC;
+ mSavedGoNegotiationConfig.wps.setup = Setup.PBC;
} else {
- mSavedGoNegotiationConfig.wpsConfig.setup = Setup.KEYPAD;
- mSavedGoNegotiationConfig.wpsConfig.pin = pin.getText().toString();
+ mSavedGoNegotiationConfig.wps.setup = Setup.KEYPAD;
+ mSavedGoNegotiationConfig.wps.pin = pin.getText().toString();
}
sendMessage(WifiP2pManager.CONNECT, mSavedGoNegotiationConfig);
mSavedGoNegotiationConfig = null;
@@ -1058,7 +1067,7 @@
})
.create();
- if (wpsConfig.setup == Setup.PBC) {
+ if (wps.setup == Setup.PBC) {
pin.setVisibility(View.GONE);
dialog.setMessage(r.getString(R.string.wifi_p2p_pbc_go_negotiation_request_message,
config.deviceAddress));
@@ -1211,6 +1220,11 @@
mReplyChannel.replyToMessage(msg, what);
}
+ private void replyToMessage(Message msg, int what, int arg1) {
+ if (msg.replyTo == null) return;
+ mReplyChannel.replyToMessage(msg, what, arg1);
+ }
+
private void replyToMessage(Message msg, int what, Object obj) {
if (msg.replyTo == null) return;
mReplyChannel.replyToMessage(msg, what, obj);
@@ -1261,5 +1275,17 @@
}
}
+ private boolean isAirplaneSensitive() {
+ String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_RADIOS);
+ return airplaneModeRadios == null
+ || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
+ }
+
+ private boolean isAirplaneModeOn() {
+ return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+ }
+
}
}