diff options
147 files changed, 4436 insertions, 1142 deletions
diff --git a/Android.mk b/Android.mk index 335fb732b214..3b0fc599ed17 100644 --- a/Android.mk +++ b/Android.mk @@ -158,6 +158,11 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/os/IResultReceiver.aidl \ core/java/com/android/internal/statusbar/IStatusBar.aidl \ core/java/com/android/internal/statusbar/IStatusBarService.aidl \ + core/java/com/android/internal/textservice/ISpellCheckerService.aidl \ + core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \ + core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \ + core/java/com/android/internal/textservice/ITextServicesManager.aidl \ + core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \ core/java/com/android/internal/view/IInputContext.aidl \ core/java/com/android/internal/view/IInputContextCallback.aidl \ core/java/com/android/internal/view/IInputMethod.aidl \ @@ -266,6 +271,11 @@ aidl_files := \ frameworks/base/core/java/android/view/Surface.aidl \ frameworks/base/core/java/android/view/WindowManager.aidl \ frameworks/base/core/java/android/widget/RemoteViews.aidl \ + frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerService.aidl \ + frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \ + frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \ + frameworks/base/core/java/com/android/internal/textservice/ITextServicesManager.aidl \ + frameworks/base/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \ frameworks/base/core/java/com/android/internal/view/IInputContext.aidl \ frameworks/base/core/java/com/android/internal/view/IInputMethod.aidl \ frameworks/base/core/java/com/android/internal/view/IInputMethodCallback.aidl \ diff --git a/api/current.txt b/api/current.txt index d821c8e75089..f88001d825f1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21,6 +21,7 @@ package android { field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN"; field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD"; field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS"; + field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE"; field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER"; field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH"; field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN"; @@ -184,14 +185,14 @@ package android { public static final class R.attr { ctor public R.attr(); field public static final int absListViewStyle = 16842858; // 0x101006a - field public static final int accessibilityEventTypes = 16843648; // 0x1010380 - field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 - field public static final int accessibilityFlags = 16843652; // 0x1010384 + field public static final int accessibilityEventTypes = 16843647; // 0x101037f + field public static final int accessibilityFeedbackType = 16843649; // 0x1010381 + field public static final int accessibilityFlags = 16843651; // 0x1010383 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 actionBarSize = 16843499; // 0x10102eb - field public static final int actionBarSplitStyle = 16843670; // 0x1010396 + field public static final int actionBarSplitStyle = 16843669; // 0x1010395 field public static final int actionBarStyle = 16843470; // 0x10102ce field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4 field public static final int actionBarTabStyle = 16843507; // 0x10102f3 @@ -207,10 +208,10 @@ package android { field public static final int actionModeCopyDrawable = 16843538; // 0x1010312 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 actionModeStyle = 16843682; // 0x10103a2 + field public static final int actionModeSelectAllDrawable = 16843645; // 0x101037d + field public static final int actionModeStyle = 16843681; // 0x10103a1 field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6 - field public static final int actionProviderClass = 16843671; // 0x1010397 + field public static final int actionProviderClass = 16843670; // 0x1010396 field public static final int actionViewClass = 16843516; // 0x10102fc field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba @@ -222,7 +223,7 @@ package android { field public static final int alertDialogIcon = 16843605; // 0x1010355 field public static final int alertDialogStyle = 16842845; // 0x101005d field public static final int alertDialogTheme = 16843529; // 0x1010309 - field public static final int alignmentMode = 16843640; // 0x1010378 + field public static final int alignmentMode = 16843639; // 0x1010377 field public static final int allContactsName = 16843468; // 0x10102cc field public static final int allowBackup = 16843392; // 0x1010280 field public static final int allowClearUserData = 16842757; // 0x1010005 @@ -256,8 +257,8 @@ package android { 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 = 16843672; // 0x1010398 + field public static final int backgroundStacked = 16843671; // 0x1010397 field public static final int backupAgent = 16843391; // 0x101027f field public static final int baseline = 16843548; // 0x101031c field public static final int baselineAlignBottom = 16843042; // 0x1010122 @@ -266,7 +267,7 @@ package android { 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 bottomChevronDrawable = 16843658; // 0x101038a field public static final int bottomDark = 16842953; // 0x10100c9 field public static final int bottomLeftRadius = 16843179; // 0x10101ab field public static final int bottomMedium = 16842958; // 0x10100ce @@ -285,7 +286,7 @@ package android { field public static final int cacheColorHint = 16843009; // 0x1010101 field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d - field public static final int canRetrieveWindowContent = 16843653; // 0x1010385 + field public static final int canRetrieveWindowContent = 16843652; // 0x1010384 field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230 field public static final deprecated int capitalize = 16843113; // 0x1010169 field public static final int centerBright = 16842956; // 0x10100cc @@ -314,18 +315,18 @@ package android { 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 = 16843677; // 0x101039d 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 = 16843676; // 0x101039c 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 columnCount = 16843637; // 0x1010375 + field public static final int colorLongPressedHighlight = 16843675; // 0x101039b + field public static final int colorMultiSelectHighlight = 16843678; // 0x101039e + field public static final int colorPressedHighlight = 16843674; // 0x101039a + field public static final int columnCount = 16843636; // 0x1010374 field public static final int columnDelay = 16843215; // 0x10101cf - field public static final int columnOrderPreserved = 16843638; // 0x1010376 + field public static final int columnOrderPreserved = 16843637; // 0x1010375 field public static final int columnWidth = 16843031; // 0x1010117 field public static final int compatibleWidthLimitDp = 16843621; // 0x1010365 field public static final int completionHint = 16843122; // 0x1010172 @@ -379,11 +380,11 @@ package android { 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 = 16843680; // 0x10103a0 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 = 16843679; // 0x101039f field public static final int drawableTop = 16843117; // 0x101016d field public static final int drawingCacheQuality = 16842984; // 0x10100e8 field public static final int dropDownAnchor = 16843363; // 0x1010263 @@ -440,7 +441,7 @@ package android { 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 feedbackCount = 16843664; // 0x1010390 field public static final int fillAfter = 16843197; // 0x10101bd field public static final int fillBefore = 16843196; // 0x10101bc field public static final int fillEnabled = 16843343; // 0x101024f @@ -493,7 +494,7 @@ package android { 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 handleDrawable = 16843654; // 0x1010386 field public static final int handleProfiling = 16842786; // 0x1010022 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e field public static final int hardwareAccelerated = 16843475; // 0x10102d3 @@ -502,12 +503,12 @@ package android { 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 hitRadius = 16843661; // 0x101038d 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 horizontalOffset = 16843666; // 0x1010392 field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353 field public static final int horizontalSpacing = 16843028; // 0x1010114 field public static final int host = 16842792; // 0x1010028 @@ -553,7 +554,7 @@ package android { field public static final int installLocation = 16843447; // 0x10102b7 field public static final int interpolator = 16843073; // 0x1010141 field public static final int isAlwaysSyncable = 16843571; // 0x1010333 - field public static final int isAuxiliary = 16843647; // 0x101037f + field public static final int isAuxiliary = 16843646; // 0x101037e field public static final int isDefault = 16843297; // 0x1010221 field public static final int isIndicator = 16843079; // 0x1010147 field public static final int isModifier = 16843334; // 0x1010246 @@ -606,8 +607,8 @@ package android { field public static final int layout_centerInParent = 16843151; // 0x101018f field public static final int layout_centerVertical = 16843153; // 0x1010191 field public static final int layout_column = 16843084; // 0x101014c - field public static final int layout_columnFlexibility = 16843645; // 0x101037d - field public static final int layout_columnSpan = 16843644; // 0x101037c + field public static final int layout_columnFlexibility = 16843644; // 0x101037c + field public static final int layout_columnSpan = 16843643; // 0x101037b field public static final int layout_gravity = 16842931; // 0x10100b3 field public static final int layout_height = 16842997; // 0x10100f5 field public static final int layout_margin = 16842998; // 0x10100f6 @@ -615,9 +616,9 @@ package android { field public static final int layout_marginLeft = 16842999; // 0x10100f7 field public static final int layout_marginRight = 16843001; // 0x10100f9 field public static final int layout_marginTop = 16843000; // 0x10100f8 - field public static final int layout_row = 16843641; // 0x1010379 - field public static final int layout_rowFlexibility = 16843643; // 0x101037b - field public static final int layout_rowSpan = 16843642; // 0x101037a + field public static final int layout_row = 16843640; // 0x1010378 + field public static final int layout_rowFlexibility = 16843642; // 0x101037a + field public static final int layout_rowSpan = 16843641; // 0x1010379 field public static final int layout_scale = 16843155; // 0x1010193 field public static final int layout_span = 16843085; // 0x101014d field public static final int layout_toLeftOf = 16843138; // 0x1010182 @@ -627,7 +628,7 @@ package android { 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 leftChevronDrawable = 16843655; // 0x1010387 field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 field public static final int lines = 16843092; // 0x1010154 @@ -639,8 +640,8 @@ package android { 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 = 16843667; // 0x1010393 + field public static final int listPreferredItemHeightSmall = 16843668; // 0x1010394 field public static final int listSelector = 16843003; // 0x10100fb field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208 field public static final int listViewStyle = 16842868; // 0x1010074 @@ -671,8 +672,8 @@ package android { field public static final int minHeight = 16843072; // 0x1010140 field public static final int minLevel = 16843185; // 0x10101b1 field public static final int minLines = 16843094; // 0x1010156 - field public static final int minResizeHeight = 16843684; // 0x10103a4 - field public static final int minResizeWidth = 16843683; // 0x10103a3 + field public static final int minResizeHeight = 16843683; // 0x10103a3 + field public static final int minResizeWidth = 16843682; // 0x10103a2 field public static final int minSdkVersion = 16843276; // 0x101020c field public static final int minWidth = 16843071; // 0x101013f field public static final int mode = 16843134; // 0x101017e @@ -688,7 +689,7 @@ package android { field public static final int nextFocusUp = 16842979; // 0x10100e3 field public static final int noHistory = 16843309; // 0x101022d field public static final int normalScreens = 16843397; // 0x1010285 - field public static final int notificationTimeout = 16843651; // 0x1010383 + field public static final int notificationTimeout = 16843650; // 0x1010382 field public static final int numColumns = 16843032; // 0x1010118 field public static final int numStars = 16843076; // 0x1010144 field public static final deprecated int numeric = 16843109; // 0x1010165 @@ -702,11 +703,11 @@ package android { 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 outerRadius = 16843660; // 0x101038c 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 packageNames = 16843649; // 0x1010381 + field public static final int packageNames = 16843648; // 0x1010380 field public static final int padding = 16842965; // 0x10100d5 field public static final int paddingBottom = 16842969; // 0x10100d9 field public static final int paddingLeft = 16842966; // 0x10100d6 @@ -791,17 +792,17 @@ package android { 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 rightChevronDrawable = 16843656; // 0x1010388 field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 field public static final int rotation = 16843558; // 0x1010326 field public static final int rotationX = 16843559; // 0x1010327 field public static final int rotationY = 16843560; // 0x1010328 - field public static final int rowCount = 16843635; // 0x1010373 + field public static final int rowCount = 16843634; // 0x1010372 field public static final int rowDelay = 16843216; // 0x10101d0 field public static final int rowEdgeFlags = 16843329; // 0x1010241 field public static final int rowHeight = 16843058; // 0x1010132 - field public static final int rowOrderPreserved = 16843636; // 0x1010374 + field public static final int rowOrderPreserved = 16843635; // 0x1010373 field public static final int saveEnabled = 16842983; // 0x10100e7 field public static final int scaleGravity = 16843262; // 0x10101fe field public static final int scaleHeight = 16843261; // 0x10101fd @@ -867,7 +868,7 @@ package android { 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 snapMargin = 16843663; // 0x101038f field public static final int soundEffectsEnabled = 16843285; // 0x1010215 field public static final int spacing = 16843027; // 0x1010113 field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087 @@ -915,7 +916,7 @@ package android { field public static final int subtitleTextStyle = 16843513; // 0x10102f9 field public static final int suggestActionMsg = 16843228; // 0x10101dc field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd - field public static final int suggestionsEnabled = 16843634; // 0x1010372 + field public static final int suggestionsEnabled = 16843633; // 0x1010371 field public static final int summary = 16843241; // 0x10101e9 field public static final int summaryColumn = 16843426; // 0x10102a2 field public static final int summaryOff = 16843248; // 0x10101f0 @@ -932,7 +933,7 @@ package android { 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 targetDrawables = 16843654; // 0x1010386 + field public static final int targetDrawables = 16843653; // 0x1010385 field public static final int targetPackage = 16842785; // 0x1010021 field public static final int targetSdkVersion = 16843376; // 0x1010270 field public static final int taskAffinity = 16842770; // 0x1010012 @@ -947,7 +948,7 @@ package android { 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 = 16843673; // 0x1010399 field public static final int textAppearance = 16842804; // 0x1010034 field public static final int textAppearanceButton = 16843271; // 0x1010207 field public static final int textAppearanceInverse = 16842805; // 0x1010035 @@ -988,9 +989,8 @@ package android { field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314 field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e - field public static final int textEditSuggestionItemLayout = 16843633; // 0x1010371 - field public static final int textEditSuggestionsBottomWindowLayout = 16843631; // 0x101036f - field public static final int textEditSuggestionsTopWindowLayout = 16843632; // 0x1010370 + field public static final int textEditSuggestionItemLayout = 16843632; // 0x1010370 + field public static final int textEditSuggestionsWindowLayout = 16843631; // 0x101036f field public static final int textFilterEnabled = 16843007; // 0x10100ff field public static final int textIsSelectable = 16843542; // 0x1010316 field public static final int textOff = 16843045; // 0x1010125 @@ -1023,7 +1023,7 @@ package android { 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 topChevronDrawable = 16843657; // 0x1010389 field public static final int topDark = 16842951; // 0x10100c7 field public static final int topLeftRadius = 16843177; // 0x10101a9 field public static final int topOffset = 16843352; // 0x1010258 @@ -1039,7 +1039,7 @@ package android { field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344 field public static final int unselectedAlpha = 16843278; // 0x101020e field public static final int updatePeriodMillis = 16843344; // 0x1010250 - field public static final int useDefaultMargins = 16843639; // 0x1010377 + field public static final int useDefaultMargins = 16843638; // 0x1010376 field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310 field public static final int useLevel = 16843167; // 0x101019f field public static final int userVisible = 16843409; // 0x1010291 @@ -1053,10 +1053,10 @@ package android { 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 verticalOffset = 16843665; // 0x1010391 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 vibrationDuration = 16843662; // 0x101038e field public static final int visibility = 16842972; // 0x10100dc field public static final int visible = 16843156; // 0x1010194 field public static final int vmSafeMode = 16843448; // 0x10102b8 @@ -1073,7 +1073,7 @@ package android { 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 waveDrawable = 16843659; // 0x101038b field public static final int webTextViewStyle = 16843449; // 0x10102b9 field public static final int webViewStyle = 16842885; // 0x1010085 field public static final int weekDayTextAppearance = 16843592; // 0x1010348 @@ -4784,6 +4784,7 @@ package android.content { field public static final java.lang.String SENSOR_SERVICE = "sensor"; field public static final java.lang.String STORAGE_SERVICE = "storage"; field public static final java.lang.String TELEPHONY_SERVICE = "phone"; + field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices"; field public static final java.lang.String UI_MODE_SERVICE = "uimode"; field public static final java.lang.String USB_SERVICE = "usb"; field public static final java.lang.String VIBRATOR_SERVICE = "vibrator"; @@ -17942,6 +17943,30 @@ package android.security { } +package android.service.textservice { + + public abstract class SpellCheckerService extends android.app.Service { + ctor public SpellCheckerService(); + method public void cancel(); + method public abstract android.view.textservice.SuggestionsInfo getSuggestions(android.view.textservice.TextInfo, int, java.lang.String); + method public android.view.textservice.SuggestionsInfo[] getSuggestionsMultiple(android.view.textservice.TextInfo[], java.lang.String, int, boolean); + method public final android.os.IBinder onBind(android.content.Intent); + field public static final java.lang.String SERVICE_INTERFACE; + } + + public class SpellCheckerSession { + method public void close(); + method public void getSuggestions(android.view.textservice.TextInfo, int); + method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean); + method public boolean isSessionDisconnected(); + } + + public static abstract interface SpellCheckerSession.SpellCheckerSessionListener { + method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]); + } + +} + package android.service.wallpaper { public abstract class WallpaperService extends android.app.Service { @@ -21005,6 +21030,11 @@ package android.view { method public void onPrepareSubMenu(android.view.SubMenu); } + public abstract interface CollapsibleActionView { + method public abstract void onActionViewCollapsed(); + method public abstract void onActionViewExpanded(); + } + public abstract interface ContextMenu implements android.view.Menu { method public abstract void clearHeader(); method public abstract android.view.ContextMenu setHeaderIcon(int); @@ -22715,10 +22745,8 @@ package android.view { ctor public ViewDebug(); method public static void dumpCapturedView(java.lang.String, java.lang.Object); method public static void startHierarchyTracing(java.lang.String, android.view.View); - method public static void startLooperProfiling(java.io.File); method public static void startRecyclerTracing(java.lang.String, android.view.View); method public static void stopHierarchyTracing(); - method public static void stopLooperProfiling(); method public static void stopRecyclerTracing(); method public static void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...); method public static void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType); @@ -24019,6 +24047,54 @@ package android.view.inputmethod { } +package android.view.textservice { + + public final class SpellCheckerInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.content.ComponentName getComponent(); + method public java.lang.String getId(); + method public java.lang.String getPackageName(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + + public final class SuggestionsInfo implements android.os.Parcelable { + ctor public SuggestionsInfo(int, java.lang.String[]); + ctor public SuggestionsInfo(int, java.lang.String[], int, int); + ctor public SuggestionsInfo(android.os.Parcel); + method public int describeContents(); + method public int getCookie(); + method public int getSequence(); + method public java.lang.String getSuggestionAt(int); + method public int getSuggestionsAttributes(); + method public int getSuggestionsCount(); + method public void setCookieAndSequence(int, int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1 + field public static final int RESULT_ATTR_LOOKS_TYPO = 4; // 0x4 + field public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 2; // 0x2 + } + + public final class TextInfo implements android.os.Parcelable { + ctor public TextInfo(java.lang.String); + ctor public TextInfo(java.lang.String, int, int); + ctor public TextInfo(android.os.Parcel); + method public int describeContents(); + method public int getCookie(); + method public int getSequence(); + method public java.lang.String getText(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + + public final class TextServicesManager { + method public android.view.textservice.SpellCheckerInfo getCurrentSpellChecker(java.util.Locale); + method public android.service.textservice.SpellCheckerSession newSpellCheckerSession(android.view.textservice.SpellCheckerInfo, java.util.Locale, android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener); + } + +} + package android.webkit { public final deprecated class CacheManager { diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 3fb17362f4c1..6dfa12be9592 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -468,10 +468,16 @@ public class Am { String profileFile = null; boolean start = false; boolean wall = false; + int profileType = 0; String process = null; String cmd = nextArgRequired(); + if ("looper".equals(cmd)) { + cmd = nextArgRequired(); + profileType = 1; + } + if ("start".equals(cmd)) { start = true; wall = "--wall".equals(nextOption()); @@ -516,7 +522,7 @@ public class Am { } else if (start) { //removeWallOption(); } - if (!mAm.profileControl(process, start, profileFile, fd)) { + if (!mAm.profileControl(process, start, profileFile, fd, profileType)) { wall = false; throw new AndroidException("PROFILE FAILED on process " + process); } @@ -1076,8 +1082,8 @@ public class Am { " am broadcast <INTENT>\n" + " am instrument [-r] [-e <NAME> <VALUE>] [-p] [-w]\n" + " [--no-window-animation] <COMPONENT>\n" + - " am profile start <PROCESS> <FILE>\n" + - " am profile stop <PROCESS>\n" + + " am profile [looper] start <PROCESS> <FILE>\n" + + " am profile [looper] stop <PROCESS>\n" + " am dumpheap [flags] <PROCESS> <FILE>\n" + " am monitor [--gdb <port>]\n" + " am screen-compat [on|off] <PACKAGE>\n" + diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 2a731a3999fc..b7cd829563c9 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1104,10 +1104,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); String process = data.readString(); boolean start = data.readInt() != 0; + int profileType = data.readInt(); String path = data.readString(); ParcelFileDescriptor fd = data.readInt() != 0 ? data.readFileDescriptor() : null; - boolean res = profileControl(process, start, path, fd); + boolean res = profileControl(process, start, path, fd, profileType); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -2888,13 +2889,14 @@ class ActivityManagerProxy implements IActivityManager } public boolean profileControl(String process, boolean start, - String path, ParcelFileDescriptor fd) throws RemoteException + String path, ParcelFileDescriptor fd, int profileType) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeString(process); data.writeInt(start ? 1 : 0); + data.writeInt(profileType); data.writeString(path); if (fd != null) { data.writeInt(1); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f6cd866d4e34..9bbbd6c76753 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -676,11 +676,12 @@ public final class ActivityThread { queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token); } - public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) { + public void profilerControl(boolean start, String path, ParcelFileDescriptor fd, + int profileType) { ProfilerControlData pcd = new ProfilerControlData(); pcd.path = path; pcd.fd = fd; - queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0); + queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0, profileType); } public void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) { @@ -954,7 +955,7 @@ public final class ActivityThread { } public void scheduleTrimMemory(int level) { - queueOrSendMessage(H.TRIM_MEMORY, level); + queueOrSendMessage(H.TRIM_MEMORY, null, level); } } @@ -1148,7 +1149,7 @@ public final class ActivityThread { handleActivityConfigurationChanged((IBinder)msg.obj); break; case PROFILER_CONTROL: - handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj); + handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj, msg.arg2); break; case CREATE_BACKUP_AGENT: handleCreateBackupAgent((CreateBackupAgentData)msg.obj); @@ -1184,8 +1185,10 @@ public final class ActivityThread { break; case UPDATE_PACKAGE_COMPATIBILITY_INFO: handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj); + break; case TRIM_MEMORY: handleTrimMemory(msg.arg1); + break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } @@ -3469,11 +3472,18 @@ public final class ActivityThread { performConfigurationChanged(r.activity, mCompatConfiguration); } - final void handleProfilerControl(boolean start, ProfilerControlData pcd) { + final void handleProfilerControl(boolean start, ProfilerControlData pcd, int profileType) { if (start) { try { - Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(), - 8 * 1024 * 1024, 0); + switch (profileType) { + case 1: + ViewDebug.startLooperProfiling(pcd.path, pcd.fd.getFileDescriptor()); + break; + default: + Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(), + 8 * 1024 * 1024, 0); + break; + } } catch (RuntimeException e) { Slog.w(TAG, "Profiling failed on path " + pcd.path + " -- can the process access this path?"); @@ -3485,7 +3495,15 @@ public final class ActivityThread { } } } else { - Debug.stopMethodTracing(); + switch (profileType) { + case 1: + ViewDebug.stopLooperProfiling(); + break; + default: + Debug.stopMethodTracing(); + break; + + } } } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 942f245bebf8..9a5b527d7c5b 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -376,10 +376,11 @@ public abstract class ApplicationThreadNative extends Binder { data.enforceInterface(IApplicationThread.descriptor); boolean start = data.readInt() != 0; + int profileType = data.readInt(); String path = data.readString(); ParcelFileDescriptor fd = data.readInt() != 0 ? data.readFileDescriptor() : null; - profilerControl(start, path, fd); + profilerControl(start, path, fd, profileType); return true; } @@ -936,10 +937,11 @@ class ApplicationThreadProxy implements IApplicationThread { } public void profilerControl(boolean start, String path, - ParcelFileDescriptor fd) throws RemoteException { + ParcelFileDescriptor fd, int profileType) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeInt(start ? 1 : 0); + data.writeInt(profileType); data.writeString(path); if (fd != null) { data.writeInt(1); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d2323e7defec..6289730cb56e 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -83,6 +83,7 @@ import android.view.ContextThemeWrapper; import android.view.WindowManagerImpl; import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.InputMethodManager; +import android.view.textservice.TextServicesManager; import android.accounts.AccountManager; import android.accounts.IAccountManager; import android.app.admin.DevicePolicyManager; @@ -320,6 +321,11 @@ class ContextImpl extends Context { return InputMethodManager.getInstance(ctx); }}); + registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + return TextServicesManager.getInstance(); + }}); + registerService(KEYGUARD_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { // TODO: why isn't this caching it? It wasn't diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 93c821c04469..64d77e80750c 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -284,7 +284,7 @@ public interface IActivityManager extends IInterface { // Turn on/off profiling in a particular process. public boolean profileControl(String process, boolean start, - String path, ParcelFileDescriptor fd) throws RemoteException; + String path, ParcelFileDescriptor fd, int profileType) throws RemoteException; public boolean shutdown(int timeout) throws RemoteException; diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 9de0bf4ffa0e..d0607d09040d 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -105,7 +105,7 @@ public interface IApplicationThread extends IInterface { throws RemoteException; void scheduleLowMemory() throws RemoteException; void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException; - void profilerControl(boolean start, String path, ParcelFileDescriptor fd) + void profilerControl(boolean start, String path, ParcelFileDescriptor fd, int profileType) throws RemoteException; void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) throws RemoteException; diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 1af09838c2f1..ca64c88e8fb7 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -97,9 +97,10 @@ public class StatusBarManager { } } - public void setIcon(String slot, int iconId, int iconLevel) { + public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) { try { - mService.setIcon(slot, mContext.getPackageName(), iconId, iconLevel); + mService.setIcon(slot, mContext.getPackageName(), iconId, iconLevel, + contentDescription); } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java index ab3a4267a7f8..095cd110eb79 100644 --- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java +++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java @@ -120,6 +120,7 @@ public final class BluetoothDeviceProfileState extends StateMachine { private Pair<Integer, String> mIncomingConnections; private PowerManager.WakeLock mWakeLock; private PowerManager mPowerManager; + private boolean mPairingRequestRcvd = false; private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -187,27 +188,38 @@ public final class BluetoothDeviceProfileState extends StateMachine { Message msg = obtainMessage(CONNECTION_ACCESS_REQUEST_REPLY); msg.arg1 = val; sendMessage(msg); + } else if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { + mPairingRequestRcvd = true; + } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { + int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, + BluetoothDevice.ERROR); + if (state == BluetoothDevice.BOND_BONDED && mPairingRequestRcvd) { + setTrust(BluetoothDevice.CONNECTION_ACCESS_YES); + mPairingRequestRcvd = false; + } else if (state == BluetoothDevice.BOND_NONE) { + mPairingRequestRcvd = false; + } } } }; private boolean isPhoneDocked(BluetoothDevice autoConnectDevice) { - // This works only because these broadcast intents are "sticky" - Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); - if (i != null) { - int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { - BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (device != null && autoConnectDevice.equals(device)) { - return true; - } - } - } - return false; - } + // This works only because these broadcast intents are "sticky" + Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + if (i != null) { + int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); + if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { + BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (device != null && autoConnectDevice.equals(device)) { + return true; + } + } + } + return false; + } public BluetoothDeviceProfileState(Context context, String address, - BluetoothService service, BluetoothA2dpService a2dpService) { + BluetoothService service, BluetoothA2dpService a2dpService, boolean setTrust) { super(address); mContext = context; mDevice = new BluetoothDevice(address); @@ -231,6 +243,8 @@ public final class BluetoothDeviceProfileState extends StateMachine { filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); + filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); + filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); mContext.registerReceiver(mBroadcastReceiver, filter); @@ -247,6 +261,10 @@ public final class BluetoothDeviceProfileState extends StateMachine { PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG); mWakeLock.setReferenceCounted(false); + + if (setTrust) { + setTrust(BluetoothDevice.CONNECTION_ACCESS_YES); + } } private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java index 92b98fd81b39..37cc1416ed81 100644 --- a/core/java/android/content/ComponentCallbacks.java +++ b/core/java/android/content/ComponentCallbacks.java @@ -56,11 +56,8 @@ public interface ComponentCallbacks { static final int TRIM_MEMORY_COMPLETE = 80; /** @hide */ - static final int TRIM_MEMORY_MODERATE = 60; + static final int TRIM_MEMORY_MODERATE = 50; /** @hide */ - static final int TRIM_MEMORY_BACKGROUND = 40; - - /** @hide */ - static final int TRIM_MEMORY_INVISIBLE = 20; + static final int TRIM_MEMORY_BACKGROUND = 20; } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index fed6d815c9f2..0a2253c8dc75 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1612,6 +1612,15 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a + * {@link android.view.textservice.TextServicesManager} for accessing + * text services. + * + * @see #getSystemService + */ + public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices"; + + /** + * Use with {@link #getSystemService} to retrieve a * {@link android.appwidget.AppWidgetManager} for accessing AppWidgets. * * @hide diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java index eafff49528f5..5cfa998857b7 100644 --- a/core/java/android/inputmethodservice/ExtractEditLayout.java +++ b/core/java/android/inputmethodservice/ExtractEditLayout.java @@ -172,7 +172,10 @@ public class ExtractEditLayout extends LinearLayout { @Override public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - return mCallback.onActionItemClicked(this, item); + if (mCallback != null) { + return mCallback.onActionItemClicked(this, item); + } + return false; } @Override diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index a866436ed77d..b035c51d3da5 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -103,6 +103,10 @@ public class EthernetDataTracker implements NetworkStateTracker { public void interfaceRemoved(String iface) { mTracker.interfaceRemoved(iface); } + + public void limitReached(String limitName, String iface) { + // Ignored. + } } private EthernetDataTracker() { diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl index 4436e6e444ee..a97f2030a146 100644 --- a/core/java/android/net/INetworkManagementEventObserver.aidl +++ b/core/java/android/net/INetworkManagementEventObserver.aidl @@ -52,4 +52,14 @@ interface INetworkManagementEventObserver { * @param iface The interface. */ void interfaceRemoved(String iface); + + /** + * A networking quota limit has been reached. The quota might not + * be specific to an interface. + * + * @param limitName The name of the limit that triggered. + * @param iface The interface on which the limit was detected. + */ + void limitReached(String limitName, String iface); + } diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java new file mode 100644 index 000000000000..458252345152 --- /dev/null +++ b/core/java/android/net/VpnBuilder.java @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.ServiceManager; + +import com.android.internal.net.VpnConfig; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.DatagramSocket; +import java.net.Socket; +import java.util.ArrayList; + +/** + * VpnBuilder is a framework which enables applications to build their + * own VPN solutions. In general, it creates a virtual network interface, + * configures addresses and routing rules, and returns a file descriptor + * to the application. Each read from the descriptor retrieves an outgoing + * packet which was routed to the interface. Each write to the descriptor + * injects an incoming packet just like it was received from the interface. + * The framework is running on Internet Protocol (IP), so packets are + * always started with IP headers. The application then completes a VPN + * connection by processing and exchanging packets with a remote server + * over a secured tunnel. + * + * <p>Letting applications intercept packets raises huge security concerns. + * Besides, a VPN application can easily break the network, and two of them + * may conflict with each other. The framework takes several actions to + * address these issues. Here are some key points: + * <ul> + * <li>User action is required to create a VPN connection.</li> + * <li>There can be only one VPN connection running at the same time. The + * existing interface is deactivated when a new one is created.</li> + * <li>A system-managed notification is shown during the lifetime of a + * VPN connection.</li> + * <li>A system-managed dialog gives the information of the current VPN + * connection. It also provides a button to disconnect.</li> + * <li>The network is restored automatically when the file descriptor is + * closed. It also covers the cases when a VPN application is crashed + * or killed by the system.</li> + * </ul> + * + * <p>There are two primary methods in this class: {@link #prepare} and + * {@link #establish}. The former deals with the user action and stops + * the existing VPN connection created by another application. The latter + * creates a VPN interface using the parameters supplied to this builder. + * An application must call {@link #prepare} to grant the right to create + * an interface, and it can be revoked at any time by another application. + * The application got revoked is notified by an {@link #ACTION_VPN_REVOKED} + * broadcast. Here are the general steps to create a VPN connection: + * <ol> + * <li>When the user press the button to connect, call {@link #prepare} + * and launch the intent if necessary.</li> + * <li>Register a receiver for {@link #ACTION_VPN_REVOKED} broadcasts. + * <li>Connect to the remote server and negotiate the network parameters + * of the VPN connection.</li> + * <li>Use those parameters to configure a VpnBuilder and create a VPN + * interface by calling {@link #establish}.</li> + * <li>Start processing packets between the returned file descriptor and + * the VPN tunnel.</li> + * <li>When an {@link #ACTION_VPN_REVOKED} broadcast is received, the + * interface is already deactivated by the framework. Close the file + * descriptor and shut down the VPN tunnel gracefully. + * </ol> + * Methods in this class can be used in activities and services. However, + * the intent returned from {@link #prepare} must be launched from an + * activity. The broadcast receiver can be registered at any time, but doing + * it before calling {@link #establish} effectively avoids race conditions. + * + * <p class="note">Using this class requires + * {@link android.Manifest.permission#VPN} permission. + * @hide + */ +public class VpnBuilder { + + /** + * Broadcast intent action indicating that the VPN application has been + * revoked. This can be only received by the target application on the + * receiver explicitly registered using {@link Context#registerReceiver}. + * + * <p>This is a protected intent that can only be sent by the system. + */ + public static final String ACTION_VPN_REVOKED = VpnConfig.ACTION_VPN_REVOKED; + + /** + * Use IConnectivityManager instead since those methods are hidden and + * not available in ConnectivityManager. + */ + private static IConnectivityManager getService() { + return IConnectivityManager.Stub.asInterface( + ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + } + + /** + * Prepare to establish a VPN connection. This method returns {@code null} + * if the VPN application is already prepared. Otherwise, it returns an + * {@link Intent} to a system activity. The application should launch the + * activity using {@link Activity#startActivityForResult} to get itself + * prepared. The activity may pop up a dialog to require user action, and + * the result will come back to the application through its + * {@link Activity#onActivityResult}. The application becomes prepared if + * the result is {@link Activity#RESULT_OK}, and it is granted to create a + * VPN interface by calling {@link #establish}. + * + * <p>Only one application can be granted at the same time. The right + * is revoked when another application is granted. The application + * losing the right will be notified by an {@link #ACTION_VPN_REVOKED} + * broadcast, and its VPN interface will be deactivated by the system. + * The application should then notify the remote server and disconnect + * gracefully. Unless the application becomes prepared again, subsequent + * calls to {@link #establish} will return {@code null}. + * + * @see #establish + * @see #ACTION_VPN_REVOKED + */ + public static Intent prepare(Context context) { + try { + if (getService().prepareVpn(context.getPackageName(), null)) { + return null; + } + } catch (RemoteException e) { + // ignore + } + return VpnConfig.getIntentForConfirmation(); + } + + private VpnConfig mConfig = new VpnConfig(); + private StringBuilder mAddresses = new StringBuilder(); + private StringBuilder mRoutes = new StringBuilder(); + + /** + * Set the name of this session. It will be displayed in system-managed + * dialogs and notifications. This is recommended not required. + */ + public VpnBuilder setSession(String session) { + mConfig.session = session; + return this; + } + + /** + * Set the {@link PendingIntent} to an activity for users to configure + * the VPN connection. If it is not set, the button to configure will + * not be shown in system-managed dialogs. + */ + public VpnBuilder setConfigureIntent(PendingIntent intent) { + mConfig.configureIntent = intent; + return this; + } + + /** + * Set the maximum transmission unit (MTU) of the VPN interface. If it + * is not set, the default value in the operating system will be used. + * + * @throws IllegalArgumentException if the value is not positive. + */ + public VpnBuilder setMtu(int mtu) { + if (mtu <= 0) { + throw new IllegalArgumentException("Bad mtu"); + } + mConfig.mtu = mtu; + return this; + } + + /** + * Private method to validate address and prefixLength. + */ + private static void check(InetAddress address, int prefixLength) { + if (address.isLoopbackAddress()) { + throw new IllegalArgumentException("Bad address"); + } + if (address instanceof Inet4Address) { + if (prefixLength < 0 || prefixLength > 32) { + throw new IllegalArgumentException("Bad prefixLength"); + } + } else if (address instanceof Inet6Address) { + if (prefixLength < 0 || prefixLength > 128) { + throw new IllegalArgumentException("Bad prefixLength"); + } + } else { + throw new IllegalArgumentException("Unsupported family"); + } + } + + /** + * Convenience method to add a network address to the VPN interface + * using a numeric address string. See {@link InetAddress} for the + * definitions of numeric address formats. + * + * @throws IllegalArgumentException if the address is invalid. + * @see #addAddress(InetAddress, int) + */ + public VpnBuilder addAddress(String address, int prefixLength) { + return addAddress(InetAddress.parseNumericAddress(address), prefixLength); + } + + /** + * Add a network address to the VPN interface. Both IPv4 and IPv6 + * addresses are supported. At least one address must be set before + * calling {@link #establish}. + * + * @throws IllegalArgumentException if the address is invalid. + */ + public VpnBuilder addAddress(InetAddress address, int prefixLength) { + check(address, prefixLength); + + if (address.isAnyLocalAddress()) { + throw new IllegalArgumentException("Bad address"); + } + + mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength)); + return this; + } + + /** + * Convenience method to add a network route to the VPN interface + * using a numeric address string. See {@link InetAddress} for the + * definitions of numeric address formats. + * + * @see #addRoute(InetAddress, int) + * @throws IllegalArgumentException if the route is invalid. + */ + public VpnBuilder addRoute(String address, int prefixLength) { + return addRoute(InetAddress.parseNumericAddress(address), prefixLength); + } + + /** + * Add a network route to the VPN interface. Both IPv4 and IPv6 + * routes are supported. + * + * @throws IllegalArgumentException if the route is invalid. + */ + public VpnBuilder addRoute(InetAddress address, int prefixLength) { + check(address, prefixLength); + + int offset = prefixLength / 8; + byte[] bytes = address.getAddress(); + if (offset < bytes.length) { + if ((byte)(bytes[offset] << (prefixLength % 8)) != 0) { + throw new IllegalArgumentException("Bad address"); + } + while (++offset < bytes.length) { + if (bytes[offset] != 0) { + throw new IllegalArgumentException("Bad address"); + } + } + } + + mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength)); + return this; + } + + /** + * Convenience method to add a DNS server to the VPN connection + * using a numeric address string. See {@link InetAddress} for the + * definitions of numeric address formats. + * + * @throws IllegalArgumentException if the address is invalid. + * @see #addDnsServer(InetAddress) + */ + public VpnBuilder addDnsServer(String address) { + return addDnsServer(InetAddress.parseNumericAddress(address)); + } + + /** + * Add a DNS server to the VPN connection. Both IPv4 and IPv6 + * addresses are supported. If none is set, the DNS servers of + * the default network will be used. + * + * @throws IllegalArgumentException if the address is invalid. + */ + public VpnBuilder addDnsServer(InetAddress address) { + if (address.isLoopbackAddress() || address.isAnyLocalAddress()) { + throw new IllegalArgumentException("Bad address"); + } + if (mConfig.dnsServers == null) { + mConfig.dnsServers = new ArrayList<String>(); + } + mConfig.dnsServers.add(address.getHostAddress()); + return this; + } + + /** + * Add a search domain to the DNS resolver. + */ + public VpnBuilder addSearchDomain(String domain) { + if (mConfig.searchDomains == null) { + mConfig.searchDomains = new ArrayList<String>(); + } + mConfig.searchDomains.add(domain); + return this; + } + + /** + * Create a VPN interface using the parameters supplied to this builder. + * The interface works on IP packets, and a file descriptor is returned + * for the application to access them. Each read retrieves an outgoing + * packet which was routed to the interface. Each write injects an + * incoming packet just like it was received from the interface. The file + * descriptor is put into non-blocking mode by default to avoid blocking + * Java threads. To use the file descriptor completely in native space, + * see {@link ParcelFileDescriptor#detachFd()}. The application MUST + * close the file descriptor when the VPN connection is terminated. The + * VPN interface will be removed and the network will be restored by the + * framework automatically. + * + * <p>To avoid conflicts, there can be only one active VPN interface at + * the same time. Usually network parameters are never changed during the + * lifetime of a VPN connection. It is also common for an application to + * create a new file descriptor after closing the previous one. However, + * it is rare but not impossible to have two interfaces while performing a + * seamless handover. In this case, the old interface will be deactivated + * when the new one is configured successfully. Both file descriptors are + * valid but now outgoing packets will be routed to the new interface. + * Therefore, after draining the old file descriptor, the application MUST + * close it and start using the new file descriptor. If the new interface + * cannot be created, the existing interface and its file descriptor remain + * untouched. + * + * <p>An exception will be thrown if the interface cannot be created for + * any reason. However, this method returns {@code null} if the application + * is not prepared or is revoked by another application. This helps solve + * possible race conditions while handling {@link #ACTION_VPN_REVOKED} + * broadcasts. + * + * @return {@link ParcelFileDescriptor} of the VPN interface, or + * {@code null} if the application is not prepared. + * @throws IllegalArgumentException if a parameter is not accepted by the + * operating system. + * @throws IllegalStateException if a parameter cannot be applied by the + * operating system. + * @see #prepare + */ + public ParcelFileDescriptor establish() { + mConfig.addresses = mAddresses.toString(); + mConfig.routes = mRoutes.toString(); + + try { + return getService().establishVpn(mConfig); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + + /** + * Protect a socket from VPN connections. The socket will be bound to the + * current default network interface, so its traffic will not be forwarded + * through VPN. This method is useful if some connections need to be kept + * outside of VPN. For example, a VPN tunnel should protect itself if its + * destination is covered by VPN routes. Otherwise its outgoing packets + * will be sent back to the VPN interface and cause an infinite loop. + * + * <p>The socket is NOT closed by this method. + * + * @return {@code true} on success. + */ + public static boolean protect(int socket) { + ParcelFileDescriptor dup = null; + try { + dup = ParcelFileDescriptor.fromFd(socket); + return getService().protectVpn(dup); + } catch (Exception e) { + return false; + } finally { + try { + dup.close(); + } catch (Exception e) { + // ignore + } + } + } + + /** + * Protect a {@link Socket} from VPN connections. + * + * @return {@code true} on success. + * @see #protect(int) + */ + public static boolean protect(Socket socket) { + return protect(socket.getFileDescriptor$().getInt$()); + } + + /** + * Protect a {@link DatagramSocket} from VPN connections. + * + * @return {@code true} on success. + * @see #protect(int) + */ + public static boolean protect(DatagramSocket socket) { + return protect(socket.getFileDescriptor$().getInt$()); + } +} diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index cd39d5cc6dee..bc372447d63e 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -361,7 +361,8 @@ public class Handler { /** * Remove any pending posts of Runnable <var>r</var> with Object - * <var>token</var> that are in the message queue. + * <var>token</var> that are in the message queue. If <var>token</var> is null, + * all callbacks will be removed. */ public final void removeCallbacks(Runnable r, Object token) { @@ -517,7 +518,8 @@ public class Handler { /** * Remove any pending posts of messages with code 'what' and whose obj is - * 'object' that are in the message queue. + * 'object' that are in the message queue. If <var>token</var> is null, + * all messages will be removed. */ public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object, true); @@ -525,7 +527,8 @@ public class Handler { /** * Remove any pending posts of callbacks and sent messages whose - * <var>obj</var> is <var>token</var>. + * <var>obj</var> is <var>token</var>. If <var>token</var> is null, + * all callbacks and messages will be removed. */ public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index c90de176896b..78c9010af8fd 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -563,6 +563,12 @@ public abstract class PreferenceActivity extends ListActivity implements // Single pane, showing just a prefs fragment. findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE); mPrefsContainer.setVisibility(View.VISIBLE); + if (initialTitle != 0) { + CharSequence initialTitleStr = getText(initialTitle); + CharSequence initialShortTitleStr = initialShortTitle != 0 + ? getText(initialShortTitle) : null; + showBreadCrumbs(initialTitleStr, initialShortTitleStr); + } } else if (mHeaders.size() > 0) { setListAdapter(new HeaderAdapter(this, mHeaders)); if (!mSinglePane) { @@ -1093,6 +1099,10 @@ public abstract class PreferenceActivity extends ListActivity implements } else { getListView().clearChoices(); } + showBreadCrumbs(header); + } + + void showBreadCrumbs(Header header) { if (header != null) { CharSequence title = header.getBreadCrumbTitle(getResources()); if (title == null) title = header.getTitle(getResources()); diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index c2998916add4..4a719ec7b9a1 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1439,6 +1439,13 @@ public final class ContactsContract { CONTENT_URI, "strequent"); /** + * The content:// style URI for showing frequently contacted person listing. + * @hide + */ + public static final Uri CONTENT_FREQUENT_URI = Uri.withAppendedPath( + CONTENT_URI, "frequent"); + + /** * The content:// style URI used for "type-to-filter" functionality on the * {@link #CONTENT_STREQUENT_URI} URI. The filter string will be used to match * various parts of the contact name. The filter argument should be passed diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index cb87e94164bb..1cd46dedd2d2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -16,8 +16,6 @@ package android.provider; - - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.SearchManager; @@ -48,7 +46,6 @@ import java.net.URISyntaxException; import java.util.HashMap; import java.util.HashSet; - /** * The Settings provider contains global system-level device preferences. */ @@ -3737,6 +3734,15 @@ public final class Settings { */ public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service"; + + /** + * The {@link ComponentName} string of the service to be used as the spell checker + * service which is one of the services managed by the text service manager. + * + * @hide + */ + public static final String SPELL_CHECKER_SERVICE = "spell_checker_service"; + /** * What happens when the user presses the Power button while in-call * and the screen is on.<br/> diff --git a/core/java/android/server/BluetoothBondState.java b/core/java/android/server/BluetoothBondState.java index 75f38f934f48..30a8b2a0dda9 100644 --- a/core/java/android/server/BluetoothBondState.java +++ b/core/java/android/server/BluetoothBondState.java @@ -21,8 +21,13 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothHeadset; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.provider.Settings; import android.util.Log; import java.io.BufferedReader; @@ -74,11 +79,17 @@ class BluetoothBondState { private BluetoothA2dp mA2dpProxy; private BluetoothHeadset mHeadsetProxy; + private ArrayList<String> mPairingRequestRcvd = new ArrayList<String>(); + BluetoothBondState(Context context, BluetoothService service) { mContext = context; mService = service; mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, mService); + + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); + mContext.registerReceiver(mReceiver, filter); } synchronized void setPendingOutgoingBonding(String address) { @@ -137,11 +148,18 @@ class BluetoothBondState { } if (state == BluetoothDevice.BOND_BONDED) { - mService.addProfileState(address); + boolean setTrust = false; + if (mPairingRequestRcvd.contains(address)) setTrust = true; + + mService.addProfileState(address, setTrust); + mPairingRequestRcvd.remove(address); + } else if (state == BluetoothDevice.BOND_BONDING) { if (mA2dpProxy == null || mHeadsetProxy == null) { getProfileProxy(); } + } else if (state == BluetoothDevice.BOND_NONE) { + mPairingRequestRcvd.remove(address); } setProfilePriorities(address, state); @@ -452,4 +470,17 @@ class BluetoothBondState { } } + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) return; + + String action = intent.getAction(); + if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { + BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + String address = dev.getAddress(); + mPairingRequestRcvd.add(address); + } + } + }; } diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index ff16c1883984..d68d8ba1e5b9 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -527,10 +527,19 @@ public class BluetoothService extends IBluetooth.Stub { break; case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY: address = (String)msg.obj; - if (address != null) { + if (address == null) return; + int attempt = mBondState.getAttempt(address); + + // Try only if attemps are in progress and cap it 2 attempts + // The 2 attempts cap is a fail safe if the stack returns + // an incorrect error code for bonding failures and if the pin + // is entered wrongly twice we should abort. + if (attempt > 0 && attempt <= 2) { + mBondState.attempt(address); createBond(address); return; } + if (attempt > 0) mBondState.clearPinAttempts(address); break; } } @@ -741,7 +750,6 @@ public class BluetoothService extends IBluetooth.Stub { BluetoothDevice.BOND_NONE, result); return; } - mBondState.attempt(address); } /*package*/ BluetoothDevice getRemoteDevice(String address) { @@ -2277,11 +2285,11 @@ public class BluetoothService extends IBluetooth.Stub { return false; } - BluetoothDeviceProfileState addProfileState(String address) { + BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) { BluetoothDeviceProfileState state = mDeviceProfileState.get(address); if (state != null) return state; - state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService); + state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust); mDeviceProfileState.put(address, state); state.start(); return state; @@ -2311,7 +2319,7 @@ public class BluetoothService extends IBluetooth.Stub { } for (String path : bonds) { String address = getAddressFromObjectPath(path); - BluetoothDeviceProfileState state = addProfileState(address); + BluetoothDeviceProfileState state = addProfileState(address, false); } } diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java new file mode 100644 index 000000000000..6ac99cab0ebf --- /dev/null +++ b/core/java/android/service/textservice/SpellCheckerService.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.service.textservice; + +import com.android.internal.textservice.ISpellCheckerService; +import com.android.internal.textservice.ISpellCheckerSession; +import com.android.internal.textservice.ISpellCheckerSessionListener; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; +import android.view.textservice.SuggestionsInfo; +import android.view.textservice.TextInfo; + +import java.lang.ref.WeakReference; + +/** + * SpellCheckerService provides an abstract base class for a spell checker. + * This class combines a service to the system with the spell checker service interface that + * spell checker must implement. + */ +public abstract class SpellCheckerService extends Service { + private static final String TAG = SpellCheckerService.class.getSimpleName(); + public static final String SERVICE_INTERFACE = SpellCheckerService.class.getName(); + + private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this); + + /** + * Get suggestions for specified text in TextInfo. + * This function will run on the incoming IPC thread. So, this is not called on the main thread, + * but will be called in series on another thread. + * @param textInfo the text metadata + * @param suggestionsLimit the number of limit of suggestions returned + * @param locale the locale for getting suggestions + * @return SuggestionInfo which contains suggestions for textInfo + */ + public abstract SuggestionsInfo getSuggestions( + TextInfo textInfo, int suggestionsLimit, String locale); + + /** + * A batch process of onGetSuggestions. + * This function will run on the incoming IPC thread. So, this is not called on the main thread, + * but will be called in series on another thread. + * @param textInfos an array of the text metadata + * @param locale the locale for getting suggestions + * @param suggestionsLimit the number of limit of suggestions returned + * @param sequentialWords true if textInfos can be treated as sequential words. + * @return an array of SuggestionInfo of onGetSuggestions + */ + public SuggestionsInfo[] getSuggestionsMultiple( + TextInfo[] textInfos, String locale, int suggestionsLimit, boolean sequentialWords) { + final int length = textInfos.length; + final SuggestionsInfo[] retval = new SuggestionsInfo[length]; + for (int i = 0; i < length; ++i) { + retval[i] = getSuggestions(textInfos[i], suggestionsLimit, locale); + retval[i].setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence()); + } + return retval; + } + + /** + * Request to abort all tasks executed in SpellChecker. + * This function will run on the incoming IPC thread. So, this is not called on the main thread, + * but will be called in series on another thread. + */ + public void cancel() {} + + /** + * Implement to return the implementation of the internal spell checker + * service interface. Subclasses should not override. + */ + @Override + public final IBinder onBind(final Intent intent) { + return mBinder; + } + + private static class SpellCheckerSessionImpl extends ISpellCheckerSession.Stub { + private final WeakReference<SpellCheckerService> mInternalServiceRef; + private final String mLocale; + private final ISpellCheckerSessionListener mListener; + + public SpellCheckerSessionImpl( + SpellCheckerService service, String locale, ISpellCheckerSessionListener listener) { + mInternalServiceRef = new WeakReference<SpellCheckerService>(service); + mLocale = locale; + mListener = listener; + } + + @Override + public void getSuggestionsMultiple( + TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { + final SpellCheckerService service = mInternalServiceRef.get(); + if (service == null) return; + try { + mListener.onGetSuggestions( + service.getSuggestionsMultiple(textInfos, mLocale, + suggestionsLimit, sequentialWords)); + } catch (RemoteException e) { + } + } + + @Override + public void cancel() { + final SpellCheckerService service = mInternalServiceRef.get(); + if (service == null) return; + service.cancel(); + } + } + + private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub { + private final WeakReference<SpellCheckerService> mInternalServiceRef; + + public SpellCheckerServiceBinder(SpellCheckerService service) { + mInternalServiceRef = new WeakReference<SpellCheckerService>(service); + } + + @Override + public ISpellCheckerSession getISpellCheckerSession( + String locale, ISpellCheckerSessionListener listener) { + final SpellCheckerService service = mInternalServiceRef.get(); + if (service == null) return null; + return new SpellCheckerSessionImpl(service, locale, listener); + } + } +} diff --git a/core/java/android/service/textservice/SpellCheckerSession.java b/core/java/android/service/textservice/SpellCheckerSession.java new file mode 100644 index 000000000000..a575220ef915 --- /dev/null +++ b/core/java/android/service/textservice/SpellCheckerSession.java @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.textservice; + +import com.android.internal.textservice.ISpellCheckerSession; +import com.android.internal.textservice.ISpellCheckerSessionListener; +import com.android.internal.textservice.ITextServicesManager; +import com.android.internal.textservice.ITextServicesSessionListener; + +import android.os.Handler; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import android.view.textservice.SuggestionsInfo; +import android.view.textservice.TextInfo; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService. + */ +public class SpellCheckerSession { + private static final String TAG = SpellCheckerSession.class.getSimpleName(); + private static final boolean DBG = false; + + private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1; + + private final InternalListener mInternalListener; + private final ITextServicesManager mTextServicesManager; + private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl; + + private boolean mIsUsed; + private SpellCheckerSessionListener mSpellCheckerSessionListener; + + /** Handler that will execute the main tasks */ + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ON_GET_SUGGESTION_MULTIPLE: + handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj); + break; + } + } + }; + + /** + * Constructor + * @hide + */ + public SpellCheckerSession(ITextServicesManager tsm, SpellCheckerSessionListener listener) { + if (listener == null || tsm == null) { + throw new NullPointerException(); + } + mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler); + mInternalListener = new InternalListener(); + mTextServicesManager = tsm; + mIsUsed = true; + mSpellCheckerSessionListener = listener; + } + + /** + * @return true if the connection to a text service of this session is disconnected and not + * alive. + */ + public boolean isSessionDisconnected() { + return mSpellCheckerSessionListenerImpl.isDisconnected(); + } + + /** + * Finish this session and allow TextServicesManagerService to disconnect the bound spell + * checker. + */ + public void close() { + mIsUsed = false; + try { + mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl); + } catch (RemoteException e) { + // do nothing + } + } + + /** + * Get candidate strings for a substring of the specified text. + * @param textInfo text metadata for a spell checker + * @param suggestionsLimit the number of limit of suggestions returned + */ + public void getSuggestions(TextInfo textInfo, int suggestionsLimit) { + getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false); + } + + /** + * A batch process of getSuggestions + * @param textInfos an array of text metadata for a spell checker + * @param suggestionsLimit the number of limit of suggestions returned + * @param sequentialWords true if textInfos can be treated as sequential words. + */ + public void getSuggestions( + TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { + // TODO: Handle multiple words suggestions by using WordBreakIterator + mSpellCheckerSessionListenerImpl.getSuggestionsMultiple( + textInfos, suggestionsLimit, sequentialWords); + } + + private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) { + mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos); + } + + private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub { + private static final int TASK_CANCEL = 1; + private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2; + private final Queue<SpellCheckerParams> mPendingTasks = + new LinkedList<SpellCheckerParams>(); + private final Handler mHandler; + + private boolean mOpened; + private ISpellCheckerSession mISpellCheckerSession; + + public SpellCheckerSessionListenerImpl(Handler handler) { + mOpened = false; + mHandler = handler; + } + + private static class SpellCheckerParams { + public final int mWhat; + public final TextInfo[] mTextInfos; + public final int mSuggestionsLimit; + public final boolean mSequentialWords; + public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit, + boolean sequentialWords) { + mWhat = what; + mTextInfos = textInfos; + mSuggestionsLimit = suggestionsLimit; + mSequentialWords = sequentialWords; + } + } + + private void processTask(SpellCheckerParams scp) { + switch (scp.mWhat) { + case TASK_CANCEL: + processCancel(); + break; + case TASK_GET_SUGGESTIONS_MULTIPLE: + processGetSuggestionsMultiple(scp); + break; + } + } + + public synchronized void onServiceConnected(ISpellCheckerSession session) { + mISpellCheckerSession = session; + mOpened = true; + if (DBG) + Log.d(TAG, "onServiceConnected - Success"); + while (!mPendingTasks.isEmpty()) { + processTask(mPendingTasks.poll()); + } + } + + public void getSuggestionsMultiple( + TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { + processOrEnqueueTask( + new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos, + suggestionsLimit, sequentialWords)); + } + + public boolean isDisconnected() { + return mOpened && mISpellCheckerSession == null; + } + + public boolean checkOpenConnection() { + if (mISpellCheckerSession != null) { + return true; + } + Log.e(TAG, "not connected to the spellchecker service."); + return false; + } + + private void processOrEnqueueTask(SpellCheckerParams scp) { + if (mISpellCheckerSession == null) { + mPendingTasks.offer(scp); + } else { + processTask(scp); + } + } + + private void processCancel() { + if (!checkOpenConnection()) { + return; + } + try { + mISpellCheckerSession.cancel(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to cancel " + e); + } + } + + private void processGetSuggestionsMultiple(SpellCheckerParams scp) { + if (!checkOpenConnection()) { + return; + } + try { + mISpellCheckerSession.getSuggestionsMultiple( + scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords); + } catch (RemoteException e) { + Log.e(TAG, "Failed to get suggestions " + e); + } + } + + @Override + public void onGetSuggestions(SuggestionsInfo[] results) { + mHandler.sendMessage(Message.obtain(mHandler, MSG_ON_GET_SUGGESTION_MULTIPLE, results)); + } + } + + /** + * Callback for getting results from text services + */ + public interface SpellCheckerSessionListener { + /** + * Callback for "getSuggestions" + * @param results an array of results of getSuggestions + */ + public void onGetSuggestions(SuggestionsInfo[] results); + } + + private class InternalListener extends ITextServicesSessionListener.Stub { + @Override + public void onServiceConnected(ISpellCheckerSession session) { + mSpellCheckerSessionListenerImpl.onServiceConnected(session); + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + if (mIsUsed) { + Log.e(TAG, "SpellCheckerSession was not finished properly." + + "You should call finishShession() when you finished to use a spell checker."); + close(); + } + } + + /** + * @hide + */ + public ITextServicesSessionListener getTextServicesSessionListener() { + return mInternalListener; + } + + /** + * @hide + */ + public ISpellCheckerSessionListener getSpellCheckerSessionListener() { + return mSpellCheckerSessionListenerImpl; + } +} diff --git a/core/java/android/view/CollapsibleActionView.java b/core/java/android/view/CollapsibleActionView.java new file mode 100644 index 000000000000..ab2365eb744c --- /dev/null +++ b/core/java/android/view/CollapsibleActionView.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.view.MenuItem.OnActionExpandListener; + +/** + * When a {@link View} implements this interface it will receive callbacks + * when expanded or collapsed as an action view alongside the optional, + * app-specified callbacks to {@link OnActionExpandListener}. + * + * <p>See {@link MenuItem} for more information about action views. + * See {@link android.app.ActionBar} for more information about the action bar. + */ +public interface CollapsibleActionView { + /** + * Called when this view is expanded as an action view. + * See {@link MenuItem#expandActionView()}. + */ + public void onActionViewExpanded(); + + /** + * Called when this view is collapsed as an action view. + * See {@link MenuItem#collapseActionView()}. + */ + public void onActionViewCollapsed(); +} diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index 4484d59a3ce4..f4c0249ab5a9 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -41,15 +41,6 @@ public abstract class DisplayList { abstract void end(); /** - * Indicates whether this display list can be replayed or not. - * - * @return True if the display list can be replayed, false otherwise. - * - * @see android.view.HardwareCanvas#drawDisplayList(DisplayList) - */ - abstract boolean isReady(); - - /** * Invalidates the display list, indicating that it should be repopulated * with new drawing commands prior to being used again. Calling this method * causes calls to {@link #isValid()} to return <code>false</code>. diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 80244bbe9244..d22fa6e501ec 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -51,6 +51,7 @@ class GLES20Canvas extends HardwareCanvas { // The native renderer will be destroyed when this object dies. // DO NOT overwrite this reference once it is set. + @SuppressWarnings("unused") private CanvasFinalizer mFinalizer; private int mWidth; @@ -97,12 +98,8 @@ class GLES20Canvas extends HardwareCanvas { protected GLES20Canvas(boolean record, boolean translucent) { mOpaque = !translucent; - setupRenderer(record); - } - - protected void setupRenderer(boolean record) { if (record) { - mRenderer = nGetDisplayListRenderer(mRenderer); + mRenderer = nCreateDisplayListRenderer(); } else { mRenderer = nCreateRenderer(); } @@ -114,43 +111,31 @@ class GLES20Canvas extends HardwareCanvas { if (mRenderer == 0) { throw new IllegalStateException("Could not create GLES20Canvas renderer"); } else { - mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer); + mFinalizer = new CanvasFinalizer(mRenderer); } } + protected void resetDisplayListRenderer() { + nResetDisplayListRenderer(mRenderer); + } + private static native int nCreateRenderer(); private static native int nCreateLayerRenderer(int layer); - private static native int nGetDisplayListRenderer(int renderer); + private static native int nCreateDisplayListRenderer(); + private static native void nResetDisplayListRenderer(int renderer); private static native void nDestroyRenderer(int renderer); - private static class CanvasFinalizer { - int mRenderer; - - // Factory method returns new instance if old one is null, or old instance - // otherwise, destroying native renderer along the way as necessary - static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) { - if (oldFinalizer == null) { - return new CanvasFinalizer(renderer); - } - oldFinalizer.replaceNativeObject(renderer); - return oldFinalizer; - } + private static final class CanvasFinalizer { + private final int mRenderer; - private CanvasFinalizer(int renderer) { + public CanvasFinalizer(int renderer) { mRenderer = renderer; } - private void replaceNativeObject(int newRenderer) { - if (mRenderer != 0 && newRenderer != mRenderer) { - nDestroyRenderer(mRenderer); - } - mRenderer = newRenderer; - } - @Override protected void finalize() throws Throwable { try { - replaceNativeObject(0); + nDestroyRenderer(mRenderer); } finally { super.finalize(); } @@ -322,11 +307,11 @@ class GLES20Canvas extends HardwareCanvas { // Display list /////////////////////////////////////////////////////////////////////////// - int getDisplayList() { - return nGetDisplayList(mRenderer); + int getDisplayList(int displayList) { + return nGetDisplayList(mRenderer, displayList); } - private static native int nGetDisplayList(int renderer); + private static native int nGetDisplayList(int renderer, int displayList); static void destroyDisplayList(int displayList) { nDestroyDisplayList(displayList); @@ -337,7 +322,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) { return nDrawDisplayList(mRenderer, - ((GLES20DisplayList) displayList).mNativeDisplayList, width, height, dirty); + ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty); } private static native boolean nDrawDisplayList(int renderer, int displayList, @@ -345,7 +330,7 @@ class GLES20Canvas extends HardwareCanvas { @Override void outputDisplayList(DisplayList displayList) { - nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList); + nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList()); } private static native void nOutputDisplayList(int renderer, int displayList); diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java index aeff31f8a193..9e649cea63dc 100644 --- a/core/java/android/view/GLES20DisplayList.java +++ b/core/java/android/view/GLES20DisplayList.java @@ -16,52 +16,50 @@ package android.view; -import java.lang.ref.WeakReference; +import android.graphics.Bitmap; + +import java.util.ArrayList; /** * An implementation of display list for OpenGL ES 2.0. */ class GLES20DisplayList extends DisplayList { - private GLES20Canvas mCanvas; - - private boolean mStarted = false; - private boolean mRecorded = false; - private boolean mValid = false; + // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long + // as the DisplayList is alive. The Bitmaps are populated by the GLES20RecordingCanvas. + final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5); - int mNativeDisplayList; - WeakReference<View> hostView; + private GLES20RecordingCanvas mCanvas; + private boolean mValid; // The native display list will be destroyed when this object dies. // DO NOT overwrite this reference once it is set. - @SuppressWarnings("unused") private DisplayListFinalizer mFinalizer; - public GLES20DisplayList(View view) { - hostView = new WeakReference<View>(view); + int getNativeDisplayList() { + if (!mValid || mFinalizer == null) { + throw new IllegalStateException("The display list is not valid."); + } + return mFinalizer.mNativeDisplayList; } @Override HardwareCanvas start() { - if (mStarted) { - throw new IllegalStateException("Recording has already started"); - } - if (mCanvas != null) { - ((GLES20RecordingCanvas) mCanvas).reset(); - } else { - mCanvas = new GLES20RecordingCanvas(true); + throw new IllegalStateException("Recording has already started"); } - mStarted = true; - mRecorded = false; - mValid = true; + mValid = false; + mCanvas = GLES20RecordingCanvas.obtain(this); + mCanvas.start(); return mCanvas; } @Override void invalidate() { - mStarted = false; - mRecorded = false; + if (mCanvas != null) { + mCanvas.recycle(); + mCanvas = null; + } mValid = false; } @@ -73,48 +71,28 @@ class GLES20DisplayList extends DisplayList { @Override void end() { if (mCanvas != null) { - mStarted = false; - mRecorded = true; - - mNativeDisplayList = mCanvas.getDisplayList(); - mFinalizer = DisplayListFinalizer.getFinalizer(mFinalizer, mNativeDisplayList); + if (mFinalizer != null) { + mCanvas.end(mFinalizer.mNativeDisplayList); + } else { + mFinalizer = new DisplayListFinalizer(mCanvas.end(0)); + } + mCanvas.recycle(); + mCanvas = null; + mValid = true; } } - @Override - boolean isReady() { - return !mStarted && mRecorded; - } - private static class DisplayListFinalizer { - int mNativeDisplayList; - - // Factory method returns new instance if old one is null, or old instance - // otherwise, destroying native display list along the way as necessary - static DisplayListFinalizer getFinalizer(DisplayListFinalizer oldFinalizer, - int nativeDisplayList) { - if (oldFinalizer == null) { - return new DisplayListFinalizer(nativeDisplayList); - } - oldFinalizer.replaceNativeObject(nativeDisplayList); - return oldFinalizer; - } + final int mNativeDisplayList; - private DisplayListFinalizer(int nativeDisplayList) { + public DisplayListFinalizer(int nativeDisplayList) { mNativeDisplayList = nativeDisplayList; } - private void replaceNativeObject(int newNativeDisplayList) { - if (mNativeDisplayList != 0 && mNativeDisplayList != newNativeDisplayList) { - GLES20Canvas.destroyDisplayList(mNativeDisplayList); - } - mNativeDisplayList = newNativeDisplayList; - } - @Override protected void finalize() throws Throwable { try { - replaceNativeObject(0); + GLES20Canvas.destroyDisplayList(mNativeDisplayList); } finally { super.finalize(); } diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java index ec94fe70ae91..078222be6fe9 100644 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -24,8 +24,10 @@ import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; - -import java.util.ArrayList; +import android.util.Pool; +import android.util.Poolable; +import android.util.PoolableManager; +import android.util.Pools; /** * An implementation of a GL canvas that records drawing operations. @@ -33,62 +35,94 @@ import java.util.ArrayList; * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while * the DisplayList is still holding a native reference to the memory. */ -class GLES20RecordingCanvas extends GLES20Canvas { - // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long - // as the DisplayList is alive. - @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"}) - private final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5); +class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> { + // The recording canvas pool should be large enough to handle a deeply nested + // view hierarchy because display lists are generated recursively. + private static final int POOL_LIMIT = 50; + + private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool( + Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() { + public GLES20RecordingCanvas newInstance() { + return new GLES20RecordingCanvas(); + } + @Override + public void onAcquired(GLES20RecordingCanvas element) { + } + @Override + public void onReleased(GLES20RecordingCanvas element) { + } + }, POOL_LIMIT)); + + private GLES20RecordingCanvas mNextPoolable; + private boolean mIsPooled; + + private GLES20DisplayList mDisplayList; - GLES20RecordingCanvas(boolean translucent) { - super(true, translucent); + private GLES20RecordingCanvas() { + super(true /*record*/, true /*translucent*/); + } + + static GLES20RecordingCanvas obtain(GLES20DisplayList displayList) { + GLES20RecordingCanvas canvas = sPool.acquire(); + canvas.mDisplayList = displayList; + return canvas; + } + + void recycle() { + mDisplayList = null; + resetDisplayListRenderer(); + sPool.release(this); + } + + void start() { + mDisplayList.mBitmaps.clear(); + } + + int end(int nativeDisplayList) { + return getDisplayList(nativeDisplayList); } private void recordShaderBitmap(Paint paint) { if (paint != null) { final Shader shader = paint.getShader(); if (shader instanceof BitmapShader) { - mBitmaps.add(((BitmapShader) shader).mBitmap); + mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap); } } } - void reset() { - mBitmaps.clear(); - setupRenderer(true); - } - @Override public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { super.drawPatch(bitmap, chunks, dst, paint); - mBitmaps.add(bitmap); + mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } @Override public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { super.drawBitmap(bitmap, left, top, paint); - mBitmaps.add(bitmap); + mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } @Override public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { super.drawBitmap(bitmap, matrix, paint); - mBitmaps.add(bitmap); + mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } @Override public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { super.drawBitmap(bitmap, src, dst, paint); - mBitmaps.add(bitmap); + mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } @Override public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { super.drawBitmap(bitmap, src, dst, paint); - mBitmaps.add(bitmap); + mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } @@ -111,7 +145,7 @@ class GLES20RecordingCanvas extends GLES20Canvas { int vertOffset, int[] colors, int colorOffset, Paint paint) { super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint); - mBitmaps.add(bitmap); + mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } @@ -270,4 +304,24 @@ class GLES20RecordingCanvas extends GLES20Canvas { colorOffset, indices, indexOffset, indexCount, paint); recordShaderBitmap(paint); } + + @Override + public GLES20RecordingCanvas getNextPoolable() { + return mNextPoolable; + } + + @Override + public void setNextPoolable(GLES20RecordingCanvas element) { + mNextPoolable = element; + } + + @Override + public boolean isPooled() { + return mIsPooled; + } + + @Override + public void setPooled(boolean isPooled) { + mIsPooled = isPooled; + } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index b865b5007200..503b54bd437d 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -189,7 +189,7 @@ public abstract class HardwareRenderer { * * @return A new display list. */ - abstract DisplayList createDisplayList(View v); + abstract DisplayList createDisplayList(); /** * Creates a new hardware layer. A hardware layer built by calling this @@ -852,8 +852,8 @@ public abstract class HardwareRenderer { } @Override - DisplayList createDisplayList(View v) { - return new GLES20DisplayList(v); + DisplayList createDisplayList() { + return new GLES20DisplayList(); } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0108ecf17b6d..ecb391d12bf1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9099,7 +9099,10 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED; } - private void resolvePadding() { + /** + * @hide + */ + protected void resolvePadding() { // If the user specified the absolute padding (either with android:padding or // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise // use the default padding or the padding from the background drawable @@ -9830,7 +9833,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit // we copy in child display lists into ours in drawChild() mRecreateDisplayList = true; if (mDisplayList == null) { - mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(this); + mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(); // If we're creating a new display list, make sure our parent gets invalidated // since they will need to recreate their display list to account for this // new child display list. diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 3798c9d0a0eb..4acf48c6b316 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -25,6 +25,7 @@ import android.os.Debug; import android.os.Environment; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.SystemClock; import android.util.DisplayMetrics; @@ -36,7 +37,7 @@ import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FileNotFoundException; +import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; @@ -50,6 +51,9 @@ import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; @@ -426,22 +430,22 @@ public class ViewDebug { * and obtain the traces. Both methods must be invoked on the * same thread. * - * @param traceFile The path where to write the looper traces - * - * @see #stopLooperProfiling() + * @hide */ - public static void startLooperProfiling(File traceFile) { + public static void startLooperProfiling(String path, FileDescriptor fileDescriptor) { if (sLooperProfilerStorage.get() == null) { - LooperProfiler profiler = new LooperProfiler(traceFile); + LooperProfiler profiler = new LooperProfiler(path, fileDescriptor); sLooperProfilerStorage.set(profiler); Looper.myLooper().setMessageLogging(profiler); } - } + } /** * Stops profiling the looper associated with the current thread. * - * @see #startLooperProfiling(java.io.File) + * @see #startLooperProfiling(String, java.io.FileDescriptor) + * + * @hide */ public static void stopLooperProfiling() { LooperProfiler profiler = sLooperProfilerStorage.get(); @@ -453,21 +457,33 @@ public class ViewDebug { } private static class LooperProfiler implements Looper.Profiler, Printer { - private static final int LOOPER_PROFILER_VERSION = 1; - private static final String LOG_TAG = "LooperProfiler"; + private static final int TRACE_VERSION_NUMBER = 3; + private static final int ACTION_EXIT_METHOD = 0x1; + private static final int HEADER_SIZE = 32; + private static final String HEADER_MAGIC = "SLOW"; + private static final short HEADER_RECORD_SIZE = (short) 14; + private final long mTraceWallStart; private final long mTraceThreadStart; private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512); - private final File mTraceFile; - private final HashMap<String, Short> mTraceNames = new HashMap<String, Short>(32); - private short mTraceId = 0; + private final HashMap<String, Integer> mTraceNames = new HashMap<String, Integer>(32); + private int mTraceId = 0; - LooperProfiler(File traceFile) { - mTraceFile = traceFile; + private final String mPath; + private ParcelFileDescriptor mFileDescriptor; + + LooperProfiler(String path, FileDescriptor fileDescriptor) { + mPath = path; + try { + mFileDescriptor = ParcelFileDescriptor.dup(fileDescriptor); + } catch (IOException e) { + Log.e(LOG_TAG, "Could not write trace file " + mPath, e); + throw new RuntimeException(e); + } mTraceWallStart = SystemClock.currentTimeMicro(); mTraceThreadStart = SystemClock.currentThreadTimeMicro(); } @@ -490,11 +506,11 @@ public class ViewDebug { mTraces.add(entry); } - private short getTraceId(Message message) { + private int getTraceId(Message message) { String name = message.getTarget().getMessageName(message); - Short traceId = mTraceNames.get(name); + Integer traceId = mTraceNames.get(name); if (traceId == null) { - traceId = mTraceId++; + traceId = mTraceId++ << 4; mTraceNames.put(name, traceId); } return traceId; @@ -507,62 +523,135 @@ public class ViewDebug { public void run() { saveTraces(); } - }, "LooperProfiler[" + mTraceFile + "]").start(); + }, "LooperProfiler[" + mPath + "]").start(); } private void saveTraces() { - FileOutputStream fos; - try { - fos = new FileOutputStream(mTraceFile); - } catch (FileNotFoundException e) { - Log.e(LOG_TAG, "Could not open trace file: " + mTraceFile); - return; - } - + FileOutputStream fos = new FileOutputStream(mFileDescriptor.getFileDescriptor()); DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); try { - out.writeInt(LOOPER_PROFILER_VERSION); - out.writeLong(mTraceWallStart); - out.writeLong(mTraceThreadStart); + writeHeader(out, mTraceWallStart, mTraceNames, mTraces); + out.flush(); - out.writeInt(mTraceNames.size()); - for (Map.Entry<String, Short> entry : mTraceNames.entrySet()) { - saveTraceName(entry.getKey(), entry.getValue(), out); - } + writeTraces(fos, out.size(), mTraceWallStart, mTraceThreadStart, mTraces); - out.writeInt(mTraces.size()); - for (Entry entry : mTraces) { - saveTrace(entry, out); - } - - Log.d(LOG_TAG, "Looper traces ready: " + mTraceFile); + Log.d(LOG_TAG, "Looper traces ready: " + mPath); } catch (IOException e) { - Log.e(LOG_TAG, "Could not write trace file: ", e); + Log.e(LOG_TAG, "Could not write trace file " + mPath, e); } finally { try { out.close(); } catch (IOException e) { - // Ignore + Log.e(LOG_TAG, "Could not write trace file " + mPath, e); + } + try { + mFileDescriptor.close(); + } catch (IOException e) { + Log.e(LOG_TAG, "Could not write trace file " + mPath, e); } } } - - private void saveTraceName(String name, short id, DataOutputStream out) throws IOException { - out.writeShort(id); - out.writeUTF(name); + + private static void writeTraces(FileOutputStream out, long offset, long wallStart, + long threadStart, ArrayList<Entry> entries) throws IOException { + + FileChannel channel = out.getChannel(); + + // Header + ByteBuffer buffer = ByteBuffer.allocateDirect(HEADER_SIZE); + buffer.put(HEADER_MAGIC.getBytes()); + buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); + buffer.putShort((short) TRACE_VERSION_NUMBER); // version + buffer.putShort((short) HEADER_SIZE); // offset to data + buffer.putLong(wallStart); // start time in usec + buffer.putShort(HEADER_RECORD_SIZE); // size of a record in bytes + // padding to 32 bytes + for (int i = 0; i < HEADER_SIZE - 18; i++) { + buffer.put((byte) 0); + } + + buffer.flip(); + channel.position(offset).write(buffer); + + buffer = ByteBuffer.allocateDirect(14).order(ByteOrder.LITTLE_ENDIAN); + for (Entry entry : entries) { + buffer.putShort((short) 1); // we simulate only one thread + buffer.putInt(entry.traceId); // entering method + buffer.putInt((int) (entry.threadStart - threadStart)); + buffer.putInt((int) (entry.wallStart - wallStart)); + + buffer.flip(); + channel.write(buffer); + buffer.clear(); + + buffer.putShort((short) 1); + buffer.putInt(entry.traceId | ACTION_EXIT_METHOD); // exiting method + buffer.putInt((int) (entry.threadStart + entry.threadTime - threadStart)); + buffer.putInt((int) (entry.wallStart + entry.wallTime - wallStart)); + + buffer.flip(); + channel.write(buffer); + buffer.clear(); + } + + channel.close(); } + + private static void writeHeader(DataOutputStream out, long start, + HashMap<String, Integer> names, ArrayList<Entry> entries) throws IOException { + + Entry last = entries.get(entries.size() - 1); + long wallTotal = (last.wallStart + last.wallTime) - start; + + startSection("version", out); + addValue(null, Integer.toString(TRACE_VERSION_NUMBER), out); + addValue("data-file-overflow", "false", out); + addValue("clock", "dual", out); + addValue("elapsed-time-usec", Long.toString(wallTotal), out); + addValue("num-method-calls", Integer.toString(entries.size()), out); + addValue("clock-call-overhead-nsec", "1", out); + addValue("vm", "dalvik", out); + + startSection("threads", out); + addThreadId(1, "main", out); + + startSection("methods", out); + addMethods(names, out); + + startSection("end", out); + } + + private static void addMethods(HashMap<String, Integer> names, DataOutputStream out) + throws IOException { + + for (Map.Entry<String, Integer> name : names.entrySet()) { + out.writeBytes(String.format("0x%08x\tEventQueue\t%s\t()V\tLooper\t-2\n", + name.getValue(), name.getKey())); + } + } + + private static void addThreadId(int id, String name, DataOutputStream out) + throws IOException { - private void saveTrace(Entry entry, DataOutputStream out) throws IOException { - out.writeShort(entry.traceId); - out.writeLong(entry.wallStart); - out.writeLong(entry.wallTime); - out.writeLong(entry.threadStart); - out.writeLong(entry.threadTime); + out.writeBytes(Integer.toString(id) + '\t' + name + '\n'); + } + + private static void addValue(String name, String value, DataOutputStream out) + throws IOException { + + if (name != null) { + out.writeBytes(name + "="); + } + out.writeBytes(value + '\n'); + } + + private static void startSection(String name, DataOutputStream out) throws IOException { + out.writeBytes("*" + name + '\n'); } static class Entry { - short traceId; + int traceId; long wallStart; long wallTime; long threadStart; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 54fee3c268e9..92a8ce7b033a 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2148,9 +2148,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager onPopulateAccessibilityEvent(event); // Let our children have a shot in populating the event. for (int i = 0, count = getChildCount(); i < count; i++) { - boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event); - if (handled) { - return handled; + View child = getChildAt(i); + if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { + boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event); + if (handled) { + return handled; + } } } return false; diff --git a/core/java/android/view/textservice/SpellCheckerInfo.aidl b/core/java/android/view/textservice/SpellCheckerInfo.aidl new file mode 100644 index 000000000000..eb5dfcc01c88 --- /dev/null +++ b/core/java/android/view/textservice/SpellCheckerInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textservice; + +parcelable SpellCheckerInfo; diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java new file mode 100644 index 000000000000..1205adfaceb3 --- /dev/null +++ b/core/java/android/view/textservice/SpellCheckerInfo.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.view.textservice; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class is used to specify meta information of an spell checker. + */ +public final class SpellCheckerInfo implements Parcelable { + private final ResolveInfo mService; + private final String mId; + + /** + * Constructor. + * @hide + */ + public SpellCheckerInfo(Context context, ResolveInfo service) { + mService = service; + ServiceInfo si = service.serviceInfo; + mId = new ComponentName(si.packageName, si.name).flattenToShortString(); + } + + /** + * Constructor. + * @hide + */ + public SpellCheckerInfo(Parcel source) { + mId = source.readString(); + mService = ResolveInfo.CREATOR.createFromParcel(source); + } + + /** + * Return a unique ID for this spell checker. The ID is generated from + * the package and class name implementing the method. + */ + public String getId() { + return mId; + } + + + /** + * Return the component of the service that implements. + */ + public ComponentName getComponent() { + return new ComponentName( + mService.serviceInfo.packageName, mService.serviceInfo.name); + } + + /** + * Return the .apk package that implements this input method. + */ + public String getPackageName() { + return mService.serviceInfo.packageName; + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mId); + mService.writeToParcel(dest, flags); + } + + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<SpellCheckerInfo> CREATOR + = new Parcelable.Creator<SpellCheckerInfo>() { + @Override + public SpellCheckerInfo createFromParcel(Parcel source) { + return new SpellCheckerInfo(source); + } + + @Override + public SpellCheckerInfo[] newArray(int size) { + return new SpellCheckerInfo[size]; + } + }; + + /** + * Used to make this class parcelable. + */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/textservice/SuggestionsInfo.aidl b/core/java/android/view/textservice/SuggestionsInfo.aidl new file mode 100644 index 000000000000..66e20d24ce1c --- /dev/null +++ b/core/java/android/view/textservice/SuggestionsInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textservice; + +parcelable SuggestionsInfo; diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java new file mode 100644 index 000000000000..b0ccbea7d91a --- /dev/null +++ b/core/java/android/view/textservice/SuggestionsInfo.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.view.textservice; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class contains a metadata of suggestions from the text service + */ +public final class SuggestionsInfo implements Parcelable { + /** + * Flag of the attributes of the suggestions that can be obtained by + * {@link #getSuggestionsAttributes}: this tells that the requested word was found + * in the dictionary in the text service. + */ + public static final int RESULT_ATTR_IN_THE_DICTIONARY = 0x0001; + /** Flag of the attributes of the suggestions that can be obtained by + * {@link #getSuggestionsAttributes}: this tells that there are one or more suggestions + * available for the requested word. This doesn't necessarily mean that the suggestions + * are actually in this SuggestionsInfo. For instance, the caller could have been asked to + * limit the maximum number of suggestions returned. + */ + public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 0x0002; + /** + * Flag of the attributes of the suggestions that can be obtained by + * {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested + * word looks a typo. + */ + public static final int RESULT_ATTR_LOOKS_TYPO = 0x0004; + private final int mSuggestionsAttributes; + private final String[] mSuggestions; + private int mCookie; + private int mSequence; + + /** + * Constructor. + * @param suggestionsAttributes from the text service + * @param suggestions from the text service + */ + public SuggestionsInfo(int suggestionsAttributes, String[] suggestions) { + if (suggestions == null) { + throw new NullPointerException(); + } + mSuggestionsAttributes = suggestionsAttributes; + mSuggestions = suggestions; + mCookie = 0; + mSequence = 0; + } + + /** + * Constructor. + * @param suggestionsAttributes from the text service + * @param suggestions from the text service + * @param cookie the cookie of the input TextInfo + * @param sequence the cookie of the input TextInfo + */ + public SuggestionsInfo( + int suggestionsAttributes, String[] suggestions, int cookie, int sequence) { + if (suggestions == null) { + throw new NullPointerException(); + } + mSuggestionsAttributes = suggestionsAttributes; + mSuggestions = suggestions; + mCookie = cookie; + mSequence = sequence; + } + + public SuggestionsInfo(Parcel source) { + mSuggestionsAttributes = source.readInt(); + mSuggestions = source.readStringArray(); + mCookie = source.readInt(); + mSequence = source.readInt(); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mSuggestionsAttributes); + dest.writeStringArray(mSuggestions); + dest.writeInt(mCookie); + dest.writeInt(mSequence); + } + + /** + * Set the cookie and the sequence of SuggestionsInfo which are set to TextInfo from a client + * application + * @param cookie the cookie of an input TextInfo + * @param sequence the cookie of an input TextInfo + */ + public void setCookieAndSequence(int cookie, int sequence) { + mCookie = cookie; + mSequence = sequence; + } + + /** + * @return the cookie which may be set by a client application + */ + public int getCookie() { + return mCookie; + } + + /** + * @return the sequence which may be set by a client application + */ + public int getSequence() { + return mSequence; + } + + /** + * @return the attributes of suggestions. This includes whether the spell checker has the word + * in its dictionary or not and whether the spell checker has confident suggestions for the + * word or not. + */ + public int getSuggestionsAttributes() { + return mSuggestionsAttributes; + } + + /** + * @return the count of suggestions + */ + public int getSuggestionsCount() { + return mSuggestions.length; + } + + /** + * @param i the id of suggestions + * @return the suggestion at the specified id + */ + public String getSuggestionAt(int i) { + return mSuggestions[i]; + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<SuggestionsInfo> CREATOR + = new Parcelable.Creator<SuggestionsInfo>() { + @Override + public SuggestionsInfo createFromParcel(Parcel source) { + return new SuggestionsInfo(source); + } + + @Override + public SuggestionsInfo[] newArray(int size) { + return new SuggestionsInfo[size]; + } + }; + + /** + * Used to make this class parcelable. + */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/textservice/TextInfo.aidl b/core/java/android/view/textservice/TextInfo.aidl new file mode 100644 index 000000000000..d231d7638a75 --- /dev/null +++ b/core/java/android/view/textservice/TextInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textservice; + +parcelable TextInfo; diff --git a/core/java/android/view/textservice/TextInfo.java b/core/java/android/view/textservice/TextInfo.java new file mode 100644 index 000000000000..b534eb0be607 --- /dev/null +++ b/core/java/android/view/textservice/TextInfo.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.view.textservice; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +/** + * This class contains a metadata of the input of TextService + */ +public final class TextInfo implements Parcelable { + private final String mText; + private final int mCookie; + private final int mSequence; + + /** + * Constructor. + * @param text the text which will be input to TextService + */ + public TextInfo(String text) { + this(text, 0, 0); + } + + /** + * Constructor. + * @param text the text which will be input to TextService + * @param cookie the cookie for this TextInfo + * @param sequence the sequence number for this TextInfo + */ + public TextInfo(String text, int cookie, int sequence) { + if (TextUtils.isEmpty(text)) { + throw new IllegalArgumentException(text); + } + mText = text; + mCookie = cookie; + mSequence = sequence; + } + + public TextInfo(Parcel source) { + mText = source.readString(); + mCookie = source.readInt(); + mSequence = source.readInt(); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mText); + dest.writeInt(mCookie); + dest.writeInt(mSequence); + } + + /** + * @return the text which is an input of a text service + */ + public String getText() { + return mText; + } + + /** + * @return the cookie of TextInfo + */ + public int getCookie() { + return mCookie; + } + + /** + * @return the sequence of TextInfo + */ + public int getSequence() { + return mSequence; + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<TextInfo> CREATOR + = new Parcelable.Creator<TextInfo>() { + @Override + public TextInfo createFromParcel(Parcel source) { + return new TextInfo(source); + } + + @Override + public TextInfo[] newArray(int size) { + return new TextInfo[size]; + } + }; + + /** + * Used to make this class parcelable. + */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java new file mode 100644 index 000000000000..6fa7e4ddf9cd --- /dev/null +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.view.textservice; + +import com.android.internal.textservice.ITextServicesManager; + +import android.content.Context; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.view.textservice.SpellCheckerInfo; +import android.service.textservice.SpellCheckerSession; +import android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener; + +import java.util.Locale; + +/** + * System API to the overall text services, which arbitrates interaction between applications + * and text services. You can retrieve an instance of this interface with + * {@link Context#getSystemService(String) Context.getSystemService()}. + * + * The user can change the current text services in Settings. And also applications can specify + * the target text services. + */ +public final class TextServicesManager { + private static final String TAG = TextServicesManager.class.getSimpleName(); + + private static TextServicesManager sInstance; + private static ITextServicesManager sService; + + private TextServicesManager() { + if (sService == null) { + IBinder b = ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE); + sService = ITextServicesManager.Stub.asInterface(b); + } + } + + /** + * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist. + * @hide + */ + public static TextServicesManager getInstance() { + synchronized (TextServicesManager.class) { + if (sInstance != null) { + return sInstance; + } + sInstance = new TextServicesManager(); + } + return sInstance; + } + + + /** + * Get the current spell checker service info for the specified locale. + * @param locale locale of a spell checker + * @return SpellCheckerInfo for the specified locale. + */ + // TODO: Add a method to get enabled spell checkers. + public SpellCheckerInfo getCurrentSpellChecker(Locale locale) { + if (locale == null) { + throw new NullPointerException("locale is null"); + } + try { + return sService.getCurrentSpellChecker(locale.toString()); + } catch (RemoteException e) { + return null; + } + } + + /** + * Get a spell checker session for a specified spell checker + * @param info SpellCheckerInfo of the spell checker + * @param locale the locale for the spell checker + * @param listener a spell checker session lister for getting results from a spell checker. + * @return the spell checker session of the spell checker + */ + public SpellCheckerSession newSpellCheckerSession( + SpellCheckerInfo info, Locale locale, SpellCheckerSessionListener listener) { + if (info == null || locale == null || listener == null) { + throw new NullPointerException(); + } + final SpellCheckerSession session = new SpellCheckerSession(sService, listener); + try { + sService.getSpellCheckerService( + info, locale.toString(), session.getTextServicesSessionListener(), + session.getSpellCheckerSessionListener()); + } catch (RemoteException e) { + return null; + } + return session; + } +} diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 73db03e44f56..6a3b2ffefae1 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -9119,20 +9119,12 @@ public class WebView extends AbsoluteLayout return nativeTileProfilingNumTilesInFrame(frame); } /** @hide only used by profiling tests */ - public int tileProfilingGetX(int frame, int tile) { - return nativeTileProfilingGetX(frame, tile); + public int tileProfilingGetInt(int frame, int tile, String key) { + return nativeTileProfilingGetInt(frame, tile, key); } /** @hide only used by profiling tests */ - public int tileProfilingGetY(int frame, int tile) { - return nativeTileProfilingGetY(frame, tile); - } - /** @hide only used by profiling tests */ - public boolean tileProfilingGetReady(int frame, int tile) { - return nativeTileProfilingGetReady(frame, tile); - } - /** @hide only used by profiling tests */ - public int tileProfilingGetLevel(int frame, int tile) { - return nativeTileProfilingGetLevel(frame, tile); + public float tileProfilingGetFloat(int frame, int tile, String key) { + return nativeTileProfilingGetFloat(frame, tile, key); } private native int nativeCacheHitFramePointer(); @@ -9262,10 +9254,8 @@ public class WebView extends AbsoluteLayout private native void nativeTileProfilingClear(); private native int nativeTileProfilingNumFrames(); private native int nativeTileProfilingNumTilesInFrame(int frame); - private native int nativeTileProfilingGetX(int frame, int tile); - private native int nativeTileProfilingGetY(int frame, int tile); - private native boolean nativeTileProfilingGetReady(int frame, int tile); - private native int nativeTileProfilingGetLevel(int frame, int tile); + private native int nativeTileProfilingGetInt(int frame, int tile, String key); + private native float nativeTileProfilingGetFloat(int frame, int tile, String key); // Never call this version except by updateCachedTextfield(String) - // we always want to pass in our generation number. private native void nativeUpdateCachedTextfield(String updatedText, diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index d7a2526003e7..8d8023bb0dd3 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1069,6 +1069,15 @@ public final class WebViewCore { + " arg1=" + msg.arg1 + " arg2=" + msg.arg2 + " obj=" + msg.obj); } + if (mWebView == null + && msg.what != EventHub.RESUME_TIMERS + && msg.what != EventHub.PAUSE_TIMERS) { + if (DebugFlags.WEB_VIEW_CORE) { + Log.v(LOGTAG, "Rejecting message " + msg.what + + " because we are destroyed"); + } + return; + } switch (msg.what) { case WEBKIT_DRAW: webkitDraw(); @@ -1757,30 +1766,17 @@ public final class WebViewCore { } /** - * Removes pending messages and trigger a DESTROY message to send to - * WebCore. + * Sends a DESTROY message to WebCore. * Called from UI thread. */ void destroy() { - // We don't want anyone to post a message between removing pending - // messages and sending the destroy message. synchronized (mEventHub) { - // RESUME_TIMERS and PAUSE_TIMERS are per process base. They need to - // be preserved even the WebView is destroyed. - // Note: we should not have more than one RESUME_TIMERS/PAUSE_TIMERS - boolean hasResume = mEventHub.hasMessages(EventHub.RESUME_TIMERS); - boolean hasPause = mEventHub.hasMessages(EventHub.PAUSE_TIMERS); - mEventHub.removeMessages(); + // Do not call removeMessages as then we risk removing PAUSE_TIMERS + // or RESUME_TIMERS messages, which we must still handle as they + // are per process. DESTROY will instead trigger a white list in + // mEventHub, skipping any remaining messages in the queue mEventHub.sendMessageAtFrontOfQueue( Message.obtain(null, EventHub.DESTROY)); - if (hasPause) { - mEventHub.sendMessageAtFrontOfQueue( - Message.obtain(null, EventHub.PAUSE_TIMERS)); - } - if (hasResume) { - mEventHub.sendMessageAtFrontOfQueue( - Message.obtain(null, EventHub.RESUME_TIMERS)); - } mEventHub.blockMessages(); } } @@ -2113,13 +2109,17 @@ public final class WebViewCore { // called from JNI or WebView thread /* package */ void contentDraw() { - // don't update the Picture until we have an initial width and finish - // the first layout - if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) { - return; - } - // only fire an event if this is our first request synchronized (this) { + if (mWebView == null || mBrowserFrame == null) { + // We were destroyed + return; + } + // don't update the Picture until we have an initial width and finish + // the first layout + if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) { + return; + } + // only fire an event if this is our first request if (mDrawIsScheduled) return; mDrawIsScheduled = true; if (mDrawIsPaused) return; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 8f8c1d069b9d..b7c1687debef 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4638,9 +4638,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te childrenTop += getVerticalFadingEdgeLength(); } } - // Don't ever focus a disabled item. - if (!mAdapter.isEnabled(i)) continue; - if (top >= childrenTop) { // Found a view whose top is fully visisble selectedPos = firstPosition + i; diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index d7429b38d2ad..4b0a6da774e9 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -317,6 +317,7 @@ public class ActivityChooserModel extends DataSetObservable { dataModel = new ActivityChooserModel(context, historyFileName); sDataModelRegistry.put(historyFileName, dataModel); } + dataModel.readHistoricalData(); return dataModel; } } @@ -505,7 +506,7 @@ public class ActivityChooserModel extends DataSetObservable { * data is read until this method is invoked. * <p> */ - public void readHistoricalData() { + private void readHistoricalData() { synchronized (mInstanceLock) { if (!mCanReadHistoricalData || !mHistoricalRecordsChanged) { return; @@ -527,7 +528,7 @@ public class ActivityChooserModel extends DataSetObservable { * @throws IllegalStateException If this method is called before a call to * {@link #readHistoricalData()}. */ - public void persistHistoricalData() { + private void persistHistoricalData() { synchronized (mInstanceLock) { if (!mReadShareHistoryCalled) { throw new IllegalStateException("No preceding call to #readHistoricalData"); @@ -629,6 +630,7 @@ public class ActivityChooserModel extends DataSetObservable { if (added) { mHistoricalRecordsChanged = true; pruneExcessiveHistoricalRecordsLocked(); + persistHistoricalData(); sortActivities(); } return added; diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 5b69aa8fb1e9..d85f8a49bdc3 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -307,7 +307,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod ActivityChooserModel dataModel = mAdapter.getDataModel(); if (dataModel != null) { dataModel.registerObserver(mModelDataSetOberver); - dataModel.readHistoricalData(); } mIsAttachedToWindow = true; } @@ -318,7 +317,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod ActivityChooserModel dataModel = mAdapter.getDataModel(); if (dataModel != null) { dataModel.unregisterObserver(mModelDataSetOberver); - dataModel.persistHistoricalData(); } mIsAttachedToWindow = false; } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 755d4e09c039..00c75a947a2a 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -902,15 +902,16 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @Override public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { - // Add a record for ourselves as well. - AccessibilityEvent record = AccessibilityEvent.obtain(); - record.setSource(this); - // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent - record.setClassName(getClass().getName()); - child.onInitializeAccessibilityEvent(record); - child.dispatchPopulateAccessibilityEvent(record); - event.appendRecord(record); - return true; + if (super.onRequestSendAccessibilityEvent(child, event)) { + // Add a record for ourselves as well. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + // Populate with the text of the requesting child. + child.dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; } @Override diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index 49616cc1ef18..f3a6da7780bb 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -39,8 +39,9 @@ public class CheckedTextView extends TextView implements Checkable { private boolean mChecked; private int mCheckMarkResource; private Drawable mCheckMarkDrawable; - private int mBasePaddingRight; + private int mBasePadding; private int mCheckMarkWidth; + private boolean mNeedRequestlayout; private static final int[] CHECKED_STATE_SET = { R.attr.state_checked @@ -123,6 +124,7 @@ public class CheckedTextView extends TextView implements Checkable { mCheckMarkDrawable.setCallback(null); unscheduleDrawable(mCheckMarkDrawable); } + mNeedRequestlayout = (d != mCheckMarkDrawable); if (d != null) { d.setCallback(this); d.setVisible(getVisibility() == VISIBLE, false); @@ -130,19 +132,35 @@ public class CheckedTextView extends TextView implements Checkable { setMinHeight(d.getIntrinsicHeight()); mCheckMarkWidth = d.getIntrinsicWidth(); - mUserPaddingRight = mCheckMarkWidth + mBasePaddingRight; d.setState(getDrawableState()); } else { - mUserPaddingRight = mBasePaddingRight; + mCheckMarkWidth = 0; } mCheckMarkDrawable = d; - requestLayout(); + // Do padding resolution. This will call setPadding() and do a requestLayout() if needed. + resolvePadding(); + } + + /** + * @hide + */ + @Override + protected void resolvePadding() { + super.resolvePadding(); + int newPadding = (mCheckMarkDrawable != null) ? + mCheckMarkWidth + mBasePadding : mBasePadding; + mNeedRequestlayout |= (mPaddingRight != newPadding); + mPaddingRight = newPadding; + if (mNeedRequestlayout) { + requestLayout(); + mNeedRequestlayout = false; + } } @Override public void setPadding(int left, int top, int right, int bottom) { super.setPadding(left, top, right, bottom); - mBasePaddingRight = mUserPaddingRight; + mBasePadding = mPaddingRight; } @Override @@ -167,9 +185,9 @@ public class CheckedTextView extends TextView implements Checkable { int right = getWidth(); checkMarkDrawable.setBounds( - right - mUserPaddingRight, + right - mPaddingRight, y, - right - mUserPaddingRight + mCheckMarkWidth, + right - mPaddingRight + mCheckMarkWidth, y + height); checkMarkDrawable.draw(canvas); } diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 161b40401327..299e1ffd2a6c 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -30,14 +30,15 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.RemotableViewMethod; import android.view.View; import android.view.ViewDebug; +import android.view.accessibility.AccessibilityEvent; import android.widget.RemoteViews.RemoteView; - /** * Displays an arbitrary image, such as an icon. The ImageView class * can load images from various sources (such as resources or content @@ -208,7 +209,15 @@ public class ImageView extends View { } return false; } - + + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + CharSequence contentDescription = getContentDescription(); + if (!TextUtils.isEmpty(contentDescription)) { + event.getText().add(contentDescription); + } + } + /** * Set this to true if you want the ImageView to adjust its bounds * to preserve the aspect ratio of its drawable. diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 108ac335fe7f..a7324b085f9b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -329,7 +329,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mTextEditPasteWindowLayout, mTextEditSidePasteWindowLayout; private int mTextEditNoPasteWindowLayout, mTextEditSideNoPasteWindowLayout; - private int mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout; + private int mTextEditSuggestionsWindowLayout; private int mTextEditSuggestionItemLayout; private SuggestionsPopupWindow mSuggestionsPopupWindow; private SuggestionRangeSpan mSuggestionRangeSpan; @@ -830,12 +830,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mTextEditSideNoPasteWindowLayout = a.getResourceId(attr, 0); break; - case com.android.internal.R.styleable.TextView_textEditSuggestionsBottomWindowLayout: - mTextEditSuggestionsBottomWindowLayout = a.getResourceId(attr, 0); - break; - - case com.android.internal.R.styleable.TextView_textEditSuggestionsTopWindowLayout: - mTextEditSuggestionsTopWindowLayout = a.getResourceId(attr, 0); + case com.android.internal.R.styleable.TextView_textEditSuggestionsWindowLayout: + mTextEditSuggestionsWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionItemLayout: @@ -8785,9 +8781,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final int MAX_NUMBER_SUGGESTIONS = 5; private static final int NO_SUGGESTIONS = -1; private final PopupWindow mContainer; - private final ViewGroup[] mSuggestionViews = new ViewGroup[2]; - private final int[] mSuggestionViewLayouts = new int[] { - mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout}; + private ViewGroup mSuggestionViewGroup; private WordIterator mSuggestionWordIterator; private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0]; @@ -8809,12 +8803,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int suggestionIndex; // the index of the suggestion inside suggestionSpan } - private ViewGroup getViewGroup(boolean under) { - final int viewIndex = under ? 0 : 1; - ViewGroup viewGroup = mSuggestionViews[viewIndex]; - - if (viewGroup == null) { - final int layout = mSuggestionViewLayouts[viewIndex]; + private void initSuggestionViewGroup() { + if (mSuggestionViewGroup == null) { LayoutInflater inflater = (LayoutInflater) TextView.this.mContext. getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -8823,19 +8813,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener "Unable to create TextEdit suggestion window inflater"); } - View view = inflater.inflate(layout, null); + View view = inflater.inflate(mTextEditSuggestionsWindowLayout, null); if (! (view instanceof ViewGroup)) { throw new IllegalArgumentException( "Inflated TextEdit suggestion window is not a ViewGroup: " + view); } - viewGroup = (ViewGroup) view; + mSuggestionViewGroup = (ViewGroup) view; // Inflate the suggestion items once and for all. for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { - View childView = inflater.inflate(mTextEditSuggestionItemLayout, viewGroup, - false); + View childView = inflater.inflate(mTextEditSuggestionItemLayout, + mSuggestionViewGroup, false); if (! (childView instanceof TextView)) { throw new IllegalArgumentException( @@ -8843,14 +8833,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } childView.setTag(new SuggestionInfo()); - viewGroup.addView(childView); + mSuggestionViewGroup.addView(childView); childView.setOnClickListener(this); } - mSuggestionViews[viewIndex] = viewGroup; + mContainer.setContentView(mSuggestionViewGroup); } - - return viewGroup; } public void show() { @@ -8861,8 +8849,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class); final int nbSpans = suggestionSpans.length; - ViewGroup viewGroup = getViewGroup(true); - mContainer.setContentView(viewGroup); + initSuggestionViewGroup(); int totalNbSuggestions = 0; int spanUnionStart = mText.length(); @@ -8878,7 +8865,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener String[] suggestions = suggestionSpan.getSuggestions(); int nbSuggestions = suggestions.length; for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) { - TextView textView = (TextView) viewGroup.getChildAt(totalNbSuggestions); + TextView textView = (TextView) mSuggestionViewGroup.getChildAt( + totalNbSuggestions); textView.setText(suggestions[suggestionIndex]); SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); suggestionInfo.spanStart = spanStart; @@ -8897,7 +8885,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (totalNbSuggestions == 0) { // TODO Replace by final text, use a dedicated layout, add a fade out timer... - TextView textView = (TextView) viewGroup.getChildAt(0); + TextView textView = (TextView) mSuggestionViewGroup.getChildAt(0); textView.setText("No suggestions available"); SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); suggestionInfo.spanStart = NO_SUGGESTIONS; @@ -8908,17 +8896,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); for (int i = 0; i < totalNbSuggestions; i++) { - final TextView textView = (TextView) viewGroup.getChildAt(i); + final TextView textView = (TextView) mSuggestionViewGroup.getChildAt(i); highlightTextDifferences(textView, spanUnionStart, spanUnionEnd); } } - for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { - viewGroup.getChildAt(i).setVisibility(i < totalNbSuggestions ? VISIBLE : GONE); + for (int i = 0; i < totalNbSuggestions; i++) { + mSuggestionViewGroup.getChildAt(i).setVisibility(VISIBLE); + } + for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) { + mSuggestionViewGroup.getChildAt(i).setVisibility(GONE); } - final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - viewGroup.measure(size, size); + final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); + final int screenWidth = displayMetrics.widthPixels; + final int screenHeight = displayMetrics.heightPixels; + mSuggestionViewGroup.measure( + View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.AT_MOST), + View.MeasureSpec.makeMeasureSpec(screenHeight, View.MeasureSpec.AT_MOST)); positionAtCursor(); } @@ -9171,23 +9166,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Vertical clipping if (coords[1] + height > screenHeight) { - // Try to position above current line instead - // TODO use top layout instead, reverse suggestion order, - // try full screen vertical down if it still does not fit. TBD with designers. - - // Update dimensions from new view - contentView = mContainer.getContentView(); - width = contentView.getMeasuredWidth(); - height = contentView.getMeasuredHeight(); - - final int lineTop = mLayout.getLineTop(line); - final int lineHeight = lineBottom - lineTop; - coords[1] -= height + lineHeight; + coords[1] = screenHeight - height; } // Horizontal clipping - coords[0] = Math.max(0, coords[0]); coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]); + coords[0] = Math.max(0, coords[0]); mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]); } diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 8d6caa17d752..2061c905ebb0 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -438,7 +438,7 @@ public class AlertController { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - topPanel.addView(mCustomTitleView, lp); + topPanel.addView(mCustomTitleView, 0, lp); // Hide the title template View titleTemplate = mWindow.findViewById(R.id.title_template); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index a9e505784930..07430e79d9a1 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -27,7 +27,7 @@ interface IStatusBarService void expand(); void collapse(); void disable(int what, IBinder token, String pkg); - void setIcon(String slot, String iconPackage, int iconId, int iconLevel); + void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription); void setIconVisibility(String slot, boolean visible); void removeIcon(String slot); void topAppWindowChanged(boolean menuVisible); diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java index ae2cac2a68f7..3333c822edaa 100644 --- a/core/java/com/android/internal/statusbar/StatusBarIcon.java +++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java @@ -19,42 +19,35 @@ package com.android.internal.statusbar; import android.os.Parcel; import android.os.Parcelable; -/** - * @hide - */ public class StatusBarIcon implements Parcelable { public String iconPackage; public int iconId; public int iconLevel; public boolean visible = true; public int number; + public CharSequence contentDescription; - private StatusBarIcon() { - } - - public StatusBarIcon(String iconPackage, int iconId, int iconLevel) { - this.iconPackage = iconPackage; - this.iconId = iconId; - this.iconLevel = iconLevel; - } - - public StatusBarIcon(String iconPackage, int iconId, int iconLevel, int number) { + public StatusBarIcon(String iconPackage, int iconId, int iconLevel, int number, + CharSequence contentDescription) { this.iconPackage = iconPackage; this.iconId = iconId; this.iconLevel = iconLevel; this.number = number; + this.contentDescription = contentDescription; } + @Override public String toString() { return "StatusBarIcon(pkg=" + this.iconPackage + " id=0x" + Integer.toHexString(this.iconId) + " level=" + this.iconLevel + " visible=" + visible + " num=" + this.number + " )"; } + @Override public StatusBarIcon clone() { - StatusBarIcon that = new StatusBarIcon(this.iconPackage, this.iconId, this.iconLevel); + StatusBarIcon that = new StatusBarIcon(this.iconPackage, this.iconId, this.iconLevel, + this.number, this.contentDescription); that.visible = this.visible; - that.number = this.number; return that; } @@ -71,6 +64,7 @@ public class StatusBarIcon implements Parcelable { this.iconLevel = in.readInt(); this.visible = in.readInt() != 0; this.number = in.readInt(); + this.contentDescription = in.readCharSequence(); } public void writeToParcel(Parcel out, int flags) { @@ -79,6 +73,7 @@ public class StatusBarIcon implements Parcelable { out.writeInt(this.iconLevel); out.writeInt(this.visible ? 1 : 0); out.writeInt(this.number); + out.writeCharSequence(this.contentDescription); } public int describeContents() { diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl new file mode 100644 index 000000000000..ff0049276bce --- /dev/null +++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl @@ -0,0 +1,29 @@ +/* + * 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.textservice; + +import com.android.internal.textservice.ISpellCheckerSession; +import com.android.internal.textservice.ISpellCheckerSessionListener; + +/** + * Public interface to the global spell checker. + * @hide + */ +interface ISpellCheckerService { + ISpellCheckerSession getISpellCheckerSession( + String locale, ISpellCheckerSessionListener listener); +} diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl new file mode 100644 index 000000000000..79e43510c00a --- /dev/null +++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl @@ -0,0 +1,28 @@ +/* + * 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.textservice; + +import android.view.textservice.TextInfo; + +/** + * @hide + */ +oneway interface ISpellCheckerSession { + void getSuggestionsMultiple( + in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords); + void cancel(); +} diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl new file mode 100644 index 000000000000..796b06eb06d6 --- /dev/null +++ b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.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.textservice; + +import android.view.textservice.SuggestionsInfo; + +/** + * @hide + */ +oneway interface ISpellCheckerSessionListener { + void onGetSuggestions(in SuggestionsInfo[] results); +} diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl new file mode 100644 index 000000000000..ad0c1ff3f816 --- /dev/null +++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl @@ -0,0 +1,35 @@ +/* + * 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.textservice; + +import com.android.internal.textservice.ISpellCheckerSessionListener; +import com.android.internal.textservice.ITextServicesSessionListener; + +import android.content.ComponentName; +import android.view.textservice.SpellCheckerInfo; + +/** + * Interface to the text service manager. + * @hide + */ +interface ITextServicesManager { + SpellCheckerInfo getCurrentSpellChecker(String locale); + oneway void getSpellCheckerService(in SpellCheckerInfo info, in String locale, + in ITextServicesSessionListener tsListener, + in ISpellCheckerSessionListener scListener); + oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener); +} diff --git a/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl new file mode 100644 index 000000000000..ecb6cd0f85d1 --- /dev/null +++ b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl @@ -0,0 +1,29 @@ +/* + * 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.textservice; + +import com.android.internal.textservice.ISpellCheckerSession; + +import android.view.textservice.SpellCheckerInfo; + +/** + * Interface to the text service session. + * @hide + */ +interface ITextServicesSessionListener { + oneway void onServiceConnected(in ISpellCheckerSession spellCheckerSession); +} diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 164d5811c31e..159b3da440bd 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -50,6 +50,8 @@ public class MenuBuilder implements Menu { private static final String LOGTAG = "MenuBuilder"; private static final String PRESENTER_KEY = "android:menu:presenters"; + private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates"; + private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview"; private static final int[] sCategoryToOrder = new int[] { 1, /* No category */ @@ -308,6 +310,67 @@ public class MenuBuilder implements Menu { dispatchRestoreInstanceState(state); } + public void saveActionViewStates(Bundle outStates) { + SparseArray<Parcelable> viewStates = null; + + final int itemCount = size(); + for (int i = 0; i < itemCount; i++) { + final MenuItem item = getItem(i); + final View v = item.getActionView(); + if (v != null && v.getId() != View.NO_ID) { + if (viewStates == null) { + viewStates = new SparseArray<Parcelable>(); + } + v.saveHierarchyState(viewStates); + if (item.isActionViewExpanded()) { + outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId()); + } + } + if (item.hasSubMenu()) { + final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + subMenu.saveActionViewStates(outStates); + } + } + + if (viewStates != null) { + outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates); + } + } + + public void restoreActionViewStates(Bundle states) { + if (states == null) { + return; + } + + SparseArray<Parcelable> viewStates = states.getSparseParcelableArray( + getActionViewStatesKey()); + + final int itemCount = size(); + for (int i = 0; i < itemCount; i++) { + final MenuItem item = getItem(i); + final View v = item.getActionView(); + if (v != null && v.getId() != View.NO_ID) { + v.restoreHierarchyState(viewStates); + } + if (item.hasSubMenu()) { + final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + subMenu.restoreActionViewStates(states); + } + } + + final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID); + if (expandedId > 0) { + MenuItem itemToExpand = findItem(expandedId); + if (itemToExpand != null) { + itemToExpand.expandActionView(); + } + } + } + + protected String getActionViewStatesKey() { + return ACTION_VIEW_STATES_KEY; + } + public void setCallback(Callback cb) { mCallback = cb; } diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 541d10120dd6..b0a002d2ce8d 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -553,6 +553,9 @@ public final class MenuItemImpl implements MenuItem { public MenuItem setActionView(View view) { mActionView = view; mActionProvider = null; + if (view != null && view.getId() == View.NO_ID && mId > 0) { + view.setId(mId); + } mMenu.onItemActionRequestChanged(this); return this; } diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java index fb1cd5e81ef7..92acf8cda8f5 100644 --- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java +++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java @@ -121,4 +121,13 @@ public class SubMenuBuilder extends MenuBuilder implements SubMenu { public boolean collapseItemActionView(MenuItemImpl item) { return mParentMenu.collapseItemActionView(item); } + + @Override + public String getActionViewStatesKey() { + final int itemId = mItem != null ? mItem.getItemId() : 0; + if (itemId == 0) { + return null; + } + return super.getActionViewStatesKey() + ":" + itemId; + } } diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index e03858b4af13..8b74f3d00428 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -42,6 +42,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; +import android.view.CollapsibleActionView; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; @@ -1304,6 +1305,10 @@ public class ActionBarView extends AbsActionBarView { if (mCustomNavView != null) mCustomNavView.setVisibility(GONE); requestLayout(); item.setActionViewExpanded(true); + + if (mExpandedActionView instanceof CollapsibleActionView) { + ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded(); + } return true; } @@ -1330,11 +1335,16 @@ public class ActionBarView extends AbsActionBarView { if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { mCustomNavView.setVisibility(VISIBLE); } + View collapsedView = mExpandedActionView; mExpandedActionView = null; mExpandedHomeLayout.setIcon(null); mCurrentExpandedItem = null; requestLayout(); item.setActionViewExpanded(false); + + if (collapsedView instanceof CollapsibleActionView) { + ((CollapsibleActionView) collapsedView).onActionViewCollapsed(); + } return true; } diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index e930c5c37638..0c81634a4a08 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -315,26 +315,56 @@ static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject) return doBooleanCommand("OK", "DRIVER STOP"); } -static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject) +/* + Multicast filtering rules work as follows: + + The driver can filter multicast (v4 and/or v6) and broadcast packets when in + a power optimized mode (typically when screen goes off). + + In order to prevent the driver from filtering the multicast/broadcast packets, we have to + add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective + + DRIVER RXFILTER-ADD Num + where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 + + and DRIVER RXFILTER-START + + In order to stop the usage of these rules, we do + + DRIVER RXFILTER-STOP + DRIVER RXFILTER-REMOVE Num + where Num is as described for RXFILTER-ADD + + The SETSUSPENDOPT driver command overrides the filtering rules +*/ + +static jboolean android_net_wifi_startMultiV4Filtering(JNIEnv* env, jobject) { - return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 0") - && doBooleanCommand("OK", "DRIVER RXFILTER-ADD 1") - && doBooleanCommand("OK", "DRIVER RXFILTER-ADD 3") + return doBooleanCommand("OK", "DRIVER RXFILTER-STOP") + && doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 2") && doBooleanCommand("OK", "DRIVER RXFILTER-START"); } -static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject) +static jboolean android_net_wifi_stopMultiV4Filtering(JNIEnv* env, jobject) { - jboolean result = doBooleanCommand("OK", "DRIVER RXFILTER-STOP"); - if (result) { - (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 3"); - (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 1"); - (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 0"); - } + return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 2") + && doBooleanCommand("OK", "DRIVER RXFILTER-START"); +} - return result; +static jboolean android_net_wifi_startMultiV6Filtering(JNIEnv* env, jobject) +{ + return doBooleanCommand("OK", "DRIVER RXFILTER-STOP") + && doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 3") + && doBooleanCommand("OK", "DRIVER RXFILTER-START"); } +static jboolean android_net_wifi_stopMultiV6Filtering(JNIEnv* env, jobject) +{ + return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 3") + && doBooleanCommand("OK", "DRIVER RXFILTER-START"); +} + + static jint android_net_wifi_getRssiHelper(const char *cmd) { char reply[BUF_SIZE]; @@ -545,8 +575,10 @@ static JNINativeMethod gWifiMethods[] = { { "setScanModeCommand", "(Z)Z", (void*) android_net_wifi_setScanModeCommand }, { "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand }, { "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand }, - { "startPacketFiltering", "()Z", (void*) android_net_wifi_startPacketFiltering }, - { "stopPacketFiltering", "()Z", (void*) android_net_wifi_stopPacketFiltering }, + { "startFilteringMulticastV4Packets", "()Z", (void*) android_net_wifi_startMultiV4Filtering}, + { "stopFilteringMulticastV4Packets", "()Z", (void*) android_net_wifi_stopMultiV4Filtering}, + { "startFilteringMulticastV6Packets", "()Z", (void*) android_net_wifi_startMultiV6Filtering}, + { "stopFilteringMulticastV6Packets", "()Z", (void*) android_net_wifi_stopMultiV6Filtering}, { "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand }, { "getPowerModeCommand", "()I", (void*) android_net_wifi_getPowerModeCommand }, { "setBandCommand", "(I)Z", (void*) android_net_wifi_setBandCommand}, diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index b0c2f2c2da07..b06de9d1b91e 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -576,18 +576,18 @@ static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz, // ---------------------------------------------------------------------------- static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env, - jobject clazz, DisplayListRenderer* renderer) { - return renderer->getDisplayList(); + jobject clazz, DisplayListRenderer* renderer, DisplayList* displayList) { + return renderer->getDisplayList(displayList); +} + +static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, + jobject clazz) { + return new DisplayListRenderer; } -static OpenGLRenderer* android_view_GLES20Canvas_getDisplayListRenderer(JNIEnv* env, +static void android_view_GLES20Canvas_resetDisplayListRenderer(JNIEnv* env, jobject clazz, DisplayListRenderer* renderer) { - if (renderer == NULL) { - renderer = new DisplayListRenderer; - } else { - renderer->reset(); - } - return renderer; + renderer->reset(); } static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env, @@ -812,9 +812,10 @@ static JNINativeMethod gMethods[] = { { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds }, - { "nGetDisplayList", "(I)I", (void*) android_view_GLES20Canvas_getDisplayList }, + { "nGetDisplayList", "(II)I", (void*) android_view_GLES20Canvas_getDisplayList }, { "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList }, - { "nGetDisplayListRenderer", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListRenderer }, + { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer }, + { "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer }, { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_drawDisplayList }, { "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 103a32691735..91003d181b9c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1120,6 +1120,13 @@ android:description="@string/permdesc_bindInputMethod" android:protectionLevel="signature" /> + <!-- Must be required by a TextService (e.g. SpellCheckerService) + to ensure that only the system can bind to it. --> + <permission android:name="android.permission.BIND_TEXT_SERVICE" + android:label="@string/permlab_bindTextService" + android:description="@string/permdesc_bindTextService" + android:protectionLevel="signature" /> + <!-- Must be required by a {@link android.service.wallpaper.WallpaperService}, to ensure that only the system can bind to it. --> <permission android:name="android.permission.BIND_WALLPAPER" @@ -1197,7 +1204,7 @@ <permission android:name="android.permission.READ_FRAME_BUFFER" android:label="@string/permlab_readFrameBuffer" android:description="@string/permdesc_readFrameBuffer" - android:protectionLevel="signature" /> + android:protectionLevel="signatureOrSystem" /> <!-- Required to be able to disable the device (very dangerous!). --> <permission android:name="android.permission.BRICK" diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_top_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_top_window.9.png Binary files differdeleted file mode 100644 index ff6b34a7ace4..000000000000 --- a/core/res/res/drawable-hdpi/text_edit_suggestions_top_window.9.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_bottom_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png Binary files differindex c97514f3ca99..c97514f3ca99 100644 --- a/core/res/res/drawable-hdpi/text_edit_suggestions_bottom_window.9.png +++ b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png Binary files differdeleted file mode 100644 index 41886eb378a5..000000000000 --- a/core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png Binary files differindex 88be6e1f96f4..88be6e1f96f4 100644 --- a/core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png +++ b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png diff --git a/core/res/res/layout/text_edit_suggestion_item.xml b/core/res/res/layout/text_edit_suggestion_item.xml index ef537d9efa93..082c5ec031c0 100644 --- a/core/res/res/layout/text_edit_suggestion_item.xml +++ b/core/res/res/layout/text_edit_suggestion_item.xml @@ -22,6 +22,8 @@ android:paddingTop="8dip" android:paddingBottom="8dip" android:layout_gravity="left|center_vertical" + android:singleLine="true" + android:ellipsize="marquee" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@android:color/dim_foreground_light" /> diff --git a/core/res/res/layout/text_edit_suggestions_bottom_window.xml b/core/res/res/layout/text_edit_suggestions_bottom_window.xml deleted file mode 100644 index 588bfbd9a321..000000000000 --- a/core/res/res/layout/text_edit_suggestions_bottom_window.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" - android:background="@android:drawable/text_edit_suggestions_bottom_window"> - -</LinearLayout> diff --git a/core/res/res/layout/text_edit_suggestions_top_window.xml b/core/res/res/layout/text_edit_suggestions_window.xml index 67faa37c32d5..824025e606f4 100644 --- a/core/res/res/layout/text_edit_suggestions_top_window.xml +++ b/core/res/res/layout/text_edit_suggestions_window.xml @@ -18,6 +18,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - android:background="@android:drawable/text_edit_suggestions_top_window"> + android:background="@android:drawable/text_edit_suggestions_window"> </LinearLayout> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 082284a5f337..7d7aea920012 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -713,10 +713,7 @@ <!-- Layout of a the view that is used to create the text suggestions popup window in an EditText. This window will be displayed below the text line. --> - <attr name="textEditSuggestionsBottomWindowLayout" format="reference" /> - <!-- Same as textEditSuggestionsBottomWindowLayout, but used when the popup is displayed - above the current line of text instead of below. --> - <attr name="textEditSuggestionsTopWindowLayout" format="reference" /> + <attr name="textEditSuggestionsWindowLayout" format="reference" /> <!-- Layout of the TextView item that will populate the suggestion popup window. --> <attr name="textEditSuggestionItemLayout" format="reference" /> @@ -3082,10 +3079,7 @@ <!-- Layout of a the view that is used to create the text suggestions popup window in an EditText. This window will be displayed below the text line. --> - <attr name="textEditSuggestionsBottomWindowLayout" /> - <!-- Same as textEditSuggestionsBottomWindowLayout, but used when the popup is displayed - above the current line of text instead of below. --> - <attr name="textEditSuggestionsTopWindowLayout" /> + <attr name="textEditSuggestionsWindowLayout" /> <!-- Layout of the TextView item that will populate the suggestion popup window. --> <attr name="textEditSuggestionItemLayout" /> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 75f0c4e78f1d..b2b7025b398d 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1715,8 +1715,7 @@ <public type="attr" name="switchPreferenceStyle" /> <public type="attr" name="textSuggestionsWindowStyle" /> - <public type="attr" name="textEditSuggestionsBottomWindowLayout" /> - <public type="attr" name="textEditSuggestionsTopWindowLayout" /> + <public type="attr" name="textEditSuggestionsWindowLayout" /> <public type="attr" name="textEditSuggestionItemLayout" /> <public type="attr" name="suggestionsEnabled" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 2e870fe43043..feac38d6d695 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -705,6 +705,12 @@ interface of an input method. Should never be needed for normal applications.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_bindTextService">bind to a text service</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_bindTextService">Allows the holder to bind to the top-level + interface of a text service(e.g. SpellCheckerService). Should never be needed for normal applications.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_bindWallpaper">bind to a wallpaper</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level @@ -2675,12 +2681,14 @@ <!-- USB_STORAGE_ERROR dialog ok button--> <string name="dlg_ok">OK</string> - <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in MTP mode. This is the title --> + <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MTP mode. This is the title --> <string name="usb_mtp_notification_title">Connected as a media device</string> - <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in PTP mode. This is the title --> + <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode. This is the title --> <string name="usb_ptp_notification_title">Connected as a camera</string> - <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in mass storage mode (for installer CD image). This is the title --> + <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in mass storage mode (for installer CD image). This is the title --> <string name="usb_cd_installer_notification_title">Connected as an installer</string> + <!-- USB_PREFERENCES: Notification for when a USB accessory is attached. This is the title --> + <string name="usb_accessory_notification_title">Connected to a USB accessory</string> <!-- See USB_PREFERENCES. This is the message. --> <string name="usb_notification_message">Touch for other USB options</string> @@ -3056,4 +3064,9 @@ <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] --> <string name="share_action_provider_share_with">Share with...</string> + <!-- Status Bar icon descriptions --> + + <!-- Description of for the status bar's icon that the device is locked for accessibility. [CHAR LIMIT=NONE] --> + <string name="status_bar_device_locked">Device locked.</string> + </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index d647467a59fc..9b6c4424e7f0 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -423,8 +423,7 @@ <item name="android:textEditNoPasteWindowLayout">?android:attr/textEditNoPasteWindowLayout</item> <item name="android:textEditSidePasteWindowLayout">?android:attr/textEditSidePasteWindowLayout</item> <item name="android:textEditSideNoPasteWindowLayout">?android:attr/textEditSideNoPasteWindowLayout</item> - <item name="android:textEditSuggestionsBottomWindowLayout">?android:attr/textEditSuggestionsBottomWindowLayout</item> - <item name="android:textEditSuggestionsTopWindowLayout">?android:attr/textEditSuggestionsTopWindowLayout</item> + <item name="android:textEditSuggestionsWindowLayout">?android:attr/textEditSuggestionsWindowLayout</item> <item name="android:textEditSuggestionItemLayout">?android:attr/textEditSuggestionItemLayout</item> <item name="android:textCursorDrawable">?android:attr/textCursorDrawable</item> </style> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 90f3602073c0..93ccfe30412a 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -190,8 +190,7 @@ <item name="textEditSidePasteWindowLayout">@android:layout/text_edit_side_paste_window</item> <item name="textEditSideNoPasteWindowLayout">@android:layout/text_edit_side_no_paste_window</item> <item name="textSuggestionsWindowStyle">@android:style/Widget.TextSuggestions</item> - <item name="textEditSuggestionsBottomWindowLayout">@android:layout/text_edit_suggestions_bottom_window</item> - <item name="textEditSuggestionsTopWindowLayout">@android:layout/text_edit_suggestions_top_window</item> + <item name="textEditSuggestionsWindowLayout">@android:layout/text_edit_suggestions_window</item> <item name="textEditSuggestionItemLayout">@android:layout/text_edit_suggestion_item</item> <item name="textCursorDrawable">@null</item> diff --git a/include/media/stagefright/openmax/OMX_IVCommon.h b/include/media/stagefright/openmax/OMX_IVCommon.h index 7ed072b73f96..97170d7e7dbe 100644 --- a/include/media/stagefright/openmax/OMX_IVCommon.h +++ b/include/media/stagefright/openmax/OMX_IVCommon.h @@ -16,29 +16,29 @@ * ------------------------------------------------------------------- */ /** - * Copyright (c) 2008 The Khronos Group Inc. - * + * Copyright (c) 2008 The Khronos Group Inc. + * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject - * to the following conditions: + * to the following conditions: * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * + * in all copies or substantial portions of the Software. + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -/** +/** * @file OMX_IVCommon.h - OpenMax IL version 1.1.2 * The structures needed by Video and Image components to exchange * parameters and configuration data with the components. @@ -53,7 +53,7 @@ extern "C" { /** * Each OMX header must include all required header files to allow the header * to compile without errors. The includes below are required for this header - * file to compile successfully + * file to compile successfully */ #include <OMX_Core.h> @@ -64,8 +64,8 @@ extern "C" { */ -/** - * Enumeration defining possible uncompressed image/video formats. +/** + * Enumeration defining possible uncompressed image/video formats. * * ENUMS: * Unused : Placeholder value when format is N/A @@ -113,7 +113,7 @@ typedef enum OMX_COLOR_FORMATTYPE { OMX_COLOR_Format16bitBGR565, OMX_COLOR_Format18bitRGB666, OMX_COLOR_Format18bitARGB1665, - OMX_COLOR_Format19bitARGB1666, + OMX_COLOR_Format19bitARGB1666, OMX_COLOR_Format24bitRGB888, OMX_COLOR_Format24bitBGR888, OMX_COLOR_Format24bitARGB1887, @@ -136,55 +136,62 @@ typedef enum OMX_COLOR_FORMATTYPE { OMX_COLOR_FormatRawBayer8bit, OMX_COLOR_FormatRawBayer10bit, OMX_COLOR_FormatRawBayer8bitcompressed, - OMX_COLOR_FormatL2, - OMX_COLOR_FormatL4, - OMX_COLOR_FormatL8, - OMX_COLOR_FormatL16, - OMX_COLOR_FormatL24, + OMX_COLOR_FormatL2, + OMX_COLOR_FormatL4, + OMX_COLOR_FormatL8, + OMX_COLOR_FormatL16, + OMX_COLOR_FormatL24, OMX_COLOR_FormatL32, OMX_COLOR_FormatYUV420PackedSemiPlanar, OMX_COLOR_FormatYUV422PackedSemiPlanar, OMX_COLOR_Format18BitBGR666, OMX_COLOR_Format24BitARGB6666, OMX_COLOR_Format24BitABGR6666, - OMX_COLOR_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_COLOR_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_COLOR_FormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ + /**<Reserved android opaque colorformat. Tells the encoder that + * the actual colorformat will be relayed by the + * Gralloc Buffers. + * FIXME: In the process of reserving some enum values for + * Android-specific OMX IL colorformats. Change this enum to + * an acceptable range once that is done.*/ + OMX_COLOR_FormatAndroidOpaque = 0x7F000001, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, OMX_COLOR_FormatMax = 0x7FFFFFFF } OMX_COLOR_FORMATTYPE; -/** +/** * Defines the matrix for conversion from RGB to YUV or vice versa. - * iColorMatrix should be initialized with the fixed point values + * iColorMatrix should be initialized with the fixed point values * used in converting between formats. */ typedef struct OMX_CONFIG_COLORCONVERSIONTYPE { OMX_U32 nSize; /**< Size of the structure in bytes */ - OMX_VERSIONTYPE nVersion; /**< OMX specification version info */ + OMX_VERSIONTYPE nVersion; /**< OMX specification version info */ OMX_U32 nPortIndex; /**< Port that this struct applies to */ OMX_S32 xColorMatrix[3][3]; /**< Stored in signed Q16 format */ OMX_S32 xColorOffset[4]; /**< Stored in signed Q16 format */ }OMX_CONFIG_COLORCONVERSIONTYPE; -/** - * Structure defining percent to scale each frame dimension. For example: +/** + * Structure defining percent to scale each frame dimension. For example: * To make the width 50% larger, use fWidth = 1.5 and to make the width * 1/2 the original size, use fWidth = 0.5 */ typedef struct OMX_CONFIG_SCALEFACTORTYPE { OMX_U32 nSize; /**< Size of the structure in bytes */ - OMX_VERSIONTYPE nVersion; /**< OMX specification version info */ + OMX_VERSIONTYPE nVersion; /**< OMX specification version info */ OMX_U32 nPortIndex; /**< Port that this struct applies to */ OMX_S32 xWidth; /**< Fixed point value stored as Q16 */ OMX_S32 xHeight; /**< Fixed point value stored as Q16 */ }OMX_CONFIG_SCALEFACTORTYPE; -/** - * Enumeration of possible image filter types +/** + * Enumeration of possible image filter types */ typedef enum OMX_IMAGEFILTERTYPE { OMX_ImageFilterNone, @@ -195,23 +202,23 @@ typedef enum OMX_IMAGEFILTERTYPE { OMX_ImageFilterOilPaint, OMX_ImageFilterHatch, OMX_ImageFilterGpen, - OMX_ImageFilterAntialias, - OMX_ImageFilterDeRing, + OMX_ImageFilterAntialias, + OMX_ImageFilterDeRing, OMX_ImageFilterSolarize, - OMX_ImageFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_ImageFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_ImageFilterVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_ImageFilterMax = 0x7FFFFFFF } OMX_IMAGEFILTERTYPE; -/** - * Image filter configuration +/** + * Image filter configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * eImageFilter : Image filter type enumeration + * nPortIndex : Port that this structure applies to + * eImageFilter : Image filter type enumeration */ typedef struct OMX_CONFIG_IMAGEFILTERTYPE { OMX_U32 nSize; @@ -221,22 +228,22 @@ typedef struct OMX_CONFIG_IMAGEFILTERTYPE { } OMX_CONFIG_IMAGEFILTERTYPE; -/** - * Customized U and V for color enhancement +/** + * Customized U and V for color enhancement * * STRUCT MEMBERS: * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * bColorEnhancement : Enable/disable color enhancement - * nCustomizedU : Practical values: 16-240, range: 0-255, value set for + * nCustomizedU : Practical values: 16-240, range: 0-255, value set for * U component - * nCustomizedV : Practical values: 16-240, range: 0-255, value set for + * nCustomizedV : Practical values: 16-240, range: 0-255, value set for * V component */ typedef struct OMX_CONFIG_COLORENHANCEMENTTYPE { OMX_U32 nSize; - OMX_VERSIONTYPE nVersion; + OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bColorEnhancement; OMX_U8 nCustomizedU; @@ -244,12 +251,12 @@ typedef struct OMX_CONFIG_COLORENHANCEMENTTYPE { } OMX_CONFIG_COLORENHANCEMENTTYPE; -/** - * Define color key and color key mask +/** + * Define color key and color key mask * * STRUCT MEMBERS: * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nARGBColor : 32bit Alpha, Red, Green, Blue Color * nARGBMask : 32bit Mask for Alpha, Red, Green, Blue channels @@ -263,12 +270,12 @@ typedef struct OMX_CONFIG_COLORKEYTYPE { } OMX_CONFIG_COLORKEYTYPE; -/** - * List of color blend types for pre/post processing +/** + * List of color blend types for pre/post processing * * ENUMS: * None : No color blending present - * AlphaConstant : Function is (alpha_constant * src) + + * AlphaConstant : Function is (alpha_constant * src) + * (1 - alpha_constant) * dst) * AlphaPerPixel : Function is (alpha * src) + (1 - alpha) * dst) * Alternate : Function is alternating pixels from src and dst @@ -284,21 +291,21 @@ typedef enum OMX_COLORBLENDTYPE { OMX_ColorBlendAnd, OMX_ColorBlendOr, OMX_ColorBlendInvert, - OMX_ColorBlendKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_ColorBlendKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_ColorBlendVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_ColorBlendMax = 0x7FFFFFFF } OMX_COLORBLENDTYPE; -/** - * Color blend configuration +/** + * Color blend configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information + * nPortIndex : Port that this structure applies to * nRGBAlphaConstant : Constant global alpha values when global alpha is used - * eColorBlend : Color blend type enumeration + * eColorBlend : Color blend type enumeration */ typedef struct OMX_CONFIG_COLORBLENDTYPE { OMX_U32 nSize; @@ -309,15 +316,15 @@ typedef struct OMX_CONFIG_COLORBLENDTYPE { } OMX_CONFIG_COLORBLENDTYPE; -/** +/** * Hold frame dimension * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * nWidth : Frame width in pixels - * nHeight : Frame height in pixels + * nPortIndex : Port that this structure applies to + * nWidth : Frame width in pixels + * nHeight : Frame height in pixels */ typedef struct OMX_FRAMESIZETYPE { OMX_U32 nSize; @@ -329,69 +336,69 @@ typedef struct OMX_FRAMESIZETYPE { /** - * Rotation configuration + * Rotation configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to - * nRotation : +/- integer rotation value + * nRotation : +/- integer rotation value */ typedef struct OMX_CONFIG_ROTATIONTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; - OMX_S32 nRotation; + OMX_S32 nRotation; } OMX_CONFIG_ROTATIONTYPE; -/** - * Possible mirroring directions for pre/post processing +/** + * Possible mirroring directions for pre/post processing * * ENUMS: - * None : No mirroring - * Vertical : Vertical mirroring, flip on X axis - * Horizontal : Horizontal mirroring, flip on Y axis + * None : No mirroring + * Vertical : Vertical mirroring, flip on X axis + * Horizontal : Horizontal mirroring, flip on Y axis * Both : Both vertical and horizontal mirroring */ typedef enum OMX_MIRRORTYPE { OMX_MirrorNone = 0, OMX_MirrorVertical, OMX_MirrorHorizontal, - OMX_MirrorBoth, - OMX_MirrorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_MirrorBoth, + OMX_MirrorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_MirrorVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ - OMX_MirrorMax = 0x7FFFFFFF + OMX_MirrorMax = 0x7FFFFFFF } OMX_MIRRORTYPE; -/** - * Mirroring configuration +/** + * Mirroring configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * eMirror : Mirror type enumeration + * nPortIndex : Port that this structure applies to + * eMirror : Mirror type enumeration */ typedef struct OMX_CONFIG_MIRRORTYPE { OMX_U32 nSize; - OMX_VERSIONTYPE nVersion; + OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_MIRRORTYPE eMirror; } OMX_CONFIG_MIRRORTYPE; -/** - * Position information only +/** + * Position information only * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to - * nX : X coordinate for the point - * nY : Y coordinate for the point - */ + * nX : X coordinate for the point + * nY : Y coordinate for the point + */ typedef struct OMX_CONFIG_POINTTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; @@ -401,37 +408,37 @@ typedef struct OMX_CONFIG_POINTTYPE { } OMX_CONFIG_POINTTYPE; -/** - * Frame size plus position +/** + * Frame size plus position * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information + * nPortIndex : Port that this structure applies to * nLeft : X Coordinate of the top left corner of the rectangle * nTop : Y Coordinate of the top left corner of the rectangle - * nWidth : Width of the rectangle - * nHeight : Height of the rectangle + * nWidth : Width of the rectangle + * nHeight : Height of the rectangle */ typedef struct OMX_CONFIG_RECTTYPE { OMX_U32 nSize; - OMX_VERSIONTYPE nVersion; - OMX_U32 nPortIndex; - OMX_S32 nLeft; + OMX_VERSIONTYPE nVersion; + OMX_U32 nPortIndex; + OMX_S32 nLeft; OMX_S32 nTop; OMX_U32 nWidth; OMX_U32 nHeight; } OMX_CONFIG_RECTTYPE; -/** - * Deblocking state; it is required to be set up before starting the codec +/** + * Deblocking state; it is required to be set up before starting the codec * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to - * bDeblocking : Enable/disable deblocking mode + * bDeblocking : Enable/disable deblocking mode */ typedef struct OMX_PARAM_DEBLOCKINGTYPE { OMX_U32 nSize; @@ -441,13 +448,13 @@ typedef struct OMX_PARAM_DEBLOCKINGTYPE { } OMX_PARAM_DEBLOCKINGTYPE; -/** - * Stabilization state +/** + * Stabilization state * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information + * nPortIndex : Port that this structure applies to * bStab : Enable/disable frame stabilization state */ typedef struct OMX_CONFIG_FRAMESTABTYPE { @@ -458,8 +465,8 @@ typedef struct OMX_CONFIG_FRAMESTABTYPE { } OMX_CONFIG_FRAMESTABTYPE; -/** - * White Balance control type +/** + * White Balance control type * * STRUCT MEMBERS: * SunLight : Referenced in JSR-234 @@ -476,20 +483,20 @@ typedef enum OMX_WHITEBALCONTROLTYPE { OMX_WhiteBalControlIncandescent, OMX_WhiteBalControlFlash, OMX_WhiteBalControlHorizon, - OMX_WhiteBalControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_WhiteBalControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_WhiteBalControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_WhiteBalControlMax = 0x7FFFFFFF } OMX_WHITEBALCONTROLTYPE; -/** - * White Balance control configuration +/** + * White Balance control configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * eWhiteBalControl : White balance enumeration + * nPortIndex : Port that this structure applies to + * eWhiteBalControl : White balance enumeration */ typedef struct OMX_CONFIG_WHITEBALCONTROLTYPE { OMX_U32 nSize; @@ -499,8 +506,8 @@ typedef struct OMX_CONFIG_WHITEBALCONTROLTYPE { } OMX_CONFIG_WHITEBALCONTROLTYPE; -/** - * Exposure control type +/** + * Exposure control type */ typedef enum OMX_EXPOSURECONTROLTYPE { OMX_ExposureControlOff = 0, @@ -513,20 +520,20 @@ typedef enum OMX_EXPOSURECONTROLTYPE { OMX_ExposureControlBeach, OMX_ExposureControlLargeAperture, OMX_ExposureControlSmallApperture, - OMX_ExposureControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_ExposureControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_ExposureControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_ExposureControlMax = 0x7FFFFFFF } OMX_EXPOSURECONTROLTYPE; -/** - * White Balance control configuration +/** + * White Balance control configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * eExposureControl : Exposure control enumeration + * nPortIndex : Port that this structure applies to + * eExposureControl : Exposure control enumeration */ typedef struct OMX_CONFIG_EXPOSURECONTROLTYPE { OMX_U32 nSize; @@ -536,16 +543,16 @@ typedef struct OMX_CONFIG_EXPOSURECONTROLTYPE { } OMX_CONFIG_EXPOSURECONTROLTYPE; -/** - * Defines sensor supported mode. +/** + * Defines sensor supported mode. * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * nFrameRate : Single shot mode is indicated by a 0 + * nPortIndex : Port that this structure applies to + * nFrameRate : Single shot mode is indicated by a 0 * bOneShot : Enable for single shot, disable for streaming - * sFrameSize : Framesize + * sFrameSize : Framesize */ typedef struct OMX_PARAM_SENSORMODETYPE { OMX_U32 nSize; @@ -557,13 +564,13 @@ typedef struct OMX_PARAM_SENSORMODETYPE { } OMX_PARAM_SENSORMODETYPE; -/** - * Defines contrast level +/** + * Defines contrast level * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information + * nPortIndex : Port that this structure applies to * nContrast : Values allowed for contrast -100 to 100, zero means no change */ typedef struct OMX_CONFIG_CONTRASTTYPE { @@ -574,14 +581,14 @@ typedef struct OMX_CONFIG_CONTRASTTYPE { } OMX_CONFIG_CONTRASTTYPE; -/** - * Defines brightness level +/** + * Defines brightness level * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information - * nPortIndex : Port that this structure applies to - * nBrightness : 0-100% + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information + * nPortIndex : Port that this structure applies to + * nBrightness : 0-100% */ typedef struct OMX_CONFIG_BRIGHTNESSTYPE { OMX_U32 nSize; @@ -591,16 +598,16 @@ typedef struct OMX_CONFIG_BRIGHTNESSTYPE { } OMX_CONFIG_BRIGHTNESSTYPE; -/** - * Defines backlight level configuration for a video sink, e.g. LCD panel +/** + * Defines backlight level configuration for a video sink, e.g. LCD panel * * STRUCT MEMBERS: * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nBacklight : Values allowed for backlight 0-100% - * nTimeout : Number of milliseconds before backlight automatically turns - * off. A value of 0x0 disables backight timeout + * nTimeout : Number of milliseconds before backlight automatically turns + * off. A value of 0x0 disables backight timeout */ typedef struct OMX_CONFIG_BACKLIGHTTYPE { OMX_U32 nSize; @@ -611,12 +618,12 @@ typedef struct OMX_CONFIG_BACKLIGHTTYPE { } OMX_CONFIG_BACKLIGHTTYPE; -/** - * Defines setting for Gamma +/** + * Defines setting for Gamma * * STRUCT MEMBERS: * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nGamma : Values allowed for gamma -100 to 100, zero means no change */ @@ -628,14 +635,14 @@ typedef struct OMX_CONFIG_GAMMATYPE { } OMX_CONFIG_GAMMATYPE; -/** - * Define for setting saturation - * +/** + * Define for setting saturation + * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to - * nSaturation : Values allowed for saturation -100 to 100, zero means + * nSaturation : Values allowed for saturation -100 to 100, zero means * no change */ typedef struct OMX_CONFIG_SATURATIONTYPE { @@ -646,14 +653,14 @@ typedef struct OMX_CONFIG_SATURATIONTYPE { } OMX_CONFIG_SATURATIONTYPE; -/** - * Define for setting Lightness +/** + * Define for setting Lightness * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to - * nLightness : Values allowed for lightness -100 to 100, zero means no + * nLightness : Values allowed for lightness -100 to 100, zero means no * change */ typedef struct OMX_CONFIG_LIGHTNESSTYPE { @@ -664,17 +671,17 @@ typedef struct OMX_CONFIG_LIGHTNESSTYPE { } OMX_CONFIG_LIGHTNESSTYPE; -/** - * Plane blend configuration +/** + * Plane blend configuration * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes + * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Index of input port associated with the plane. - * nDepth : Depth of the plane in relation to the screen. Higher - * numbered depths are "behind" lower number depths. + * nDepth : Depth of the plane in relation to the screen. Higher + * numbered depths are "behind" lower number depths. * This number defaults to the Port Index number. - * nAlpha : Transparency blending component for the entire plane. + * nAlpha : Transparency blending component for the entire plane. * See blending modes for more detail. */ typedef struct OMX_CONFIG_PLANEBLENDTYPE { @@ -686,17 +693,17 @@ typedef struct OMX_CONFIG_PLANEBLENDTYPE { } OMX_CONFIG_PLANEBLENDTYPE; -/** +/** * Define interlace type * * STRUCT MEMBERS: - * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to - * bEnable : Enable control variable for this functionality + * bEnable : Enable control variable for this functionality * (see below) - * nInterleavePortIndex : Index of input or output port associated with - * the interleaved plane. + * nInterleavePortIndex : Index of input or output port associated with + * the interleaved plane. * pPlanarPortIndexes[4] : Index of input or output planar ports. */ typedef struct OMX_PARAM_INTERLEAVETYPE { @@ -708,8 +715,8 @@ typedef struct OMX_PARAM_INTERLEAVETYPE { } OMX_PARAM_INTERLEAVETYPE; -/** - * Defines the picture effect used for an input picture +/** + * Defines the picture effect used for an input picture */ typedef enum OMX_TRANSITIONEFFECTTYPE { OMX_EffectNone, @@ -719,18 +726,18 @@ typedef enum OMX_TRANSITIONEFFECTTYPE { OMX_EffectDissolve, OMX_EffectWipe, OMX_EffectUnspecifiedMixOfTwoScenes, - OMX_EffectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_EffectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_EffectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_EffectMax = 0x7FFFFFFF } OMX_TRANSITIONEFFECTTYPE; -/** - * Structure used to configure current transition effect +/** + * Structure used to configure current transition effect * * STRUCT MEMBERS: * nSize : Size of the structure in bytes - * nVersion : OMX specification version information + * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eEffect : Effect to enable */ @@ -742,43 +749,43 @@ typedef struct OMX_CONFIG_TRANSITIONEFFECTTYPE { } OMX_CONFIG_TRANSITIONEFFECTTYPE; -/** - * Defines possible data unit types for encoded video data. The data unit +/** + * Defines possible data unit types for encoded video data. The data unit * types are used both for encoded video input for playback as well as - * encoded video output from recording. + * encoded video output from recording. */ typedef enum OMX_DATAUNITTYPE { OMX_DataUnitCodedPicture, OMX_DataUnitVideoSegment, OMX_DataUnitSeveralSegments, OMX_DataUnitArbitraryStreamSection, - OMX_DataUnitKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_DataUnitKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_DataUnitVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_DataUnitMax = 0x7FFFFFFF } OMX_DATAUNITTYPE; -/** - * Defines possible encapsulation types for coded video data unit. The - * encapsulation information is used both for encoded video input for - * playback as well as encoded video output from recording. +/** + * Defines possible encapsulation types for coded video data unit. The + * encapsulation information is used both for encoded video input for + * playback as well as encoded video output from recording. */ typedef enum OMX_DATAUNITENCAPSULATIONTYPE { OMX_DataEncapsulationElementaryStream, OMX_DataEncapsulationGenericPayload, OMX_DataEncapsulationRtpPayload, - OMX_DataEncapsulationKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_DataEncapsulationKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_DataEncapsulationVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_DataEncapsulationMax = 0x7FFFFFFF } OMX_DATAUNITENCAPSULATIONTYPE; -/** - * Structure used to configure the type of being decoded/encoded +/** + * Structure used to configure the type of being decoded/encoded */ typedef struct OMX_PARAM_DATAUNITTYPE { OMX_U32 nSize; /**< Size of the structure in bytes */ - OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ + OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port that this structure applies to */ OMX_DATAUNITTYPE eUnitType; OMX_DATAUNITENCAPSULATIONTYPE eEncapsulationType; @@ -786,25 +793,25 @@ typedef struct OMX_PARAM_DATAUNITTYPE { /** - * Defines dither types + * Defines dither types */ typedef enum OMX_DITHERTYPE { OMX_DitherNone, OMX_DitherOrdered, OMX_DitherErrorDiffusion, OMX_DitherOther, - OMX_DitherKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_DitherKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_DitherVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_DitherMax = 0x7FFFFFFF } OMX_DITHERTYPE; -/** - * Structure used to configure current type of dithering +/** + * Structure used to configure current type of dithering */ typedef struct OMX_CONFIG_DITHERTYPE { OMX_U32 nSize; /**< Size of the structure in bytes */ - OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ + OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port that this structure applies to */ OMX_DITHERTYPE eDither; /**< Type of dithering to use */ } OMX_CONFIG_DITHERTYPE; @@ -813,28 +820,28 @@ typedef struct OMX_CONFIG_CAPTUREMODETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; /**< Port that this structure applies to */ - OMX_BOOL bContinuous; /**< If true then ignore frame rate and emit capture + OMX_BOOL bContinuous; /**< If true then ignore frame rate and emit capture * data as fast as possible (otherwise obey port's frame rate). */ - OMX_BOOL bFrameLimited; /**< If true then terminate capture after the port emits the - * specified number of frames (otherwise the port does not - * terminate the capture until instructed to do so by the client). - * Even if set, the client may manually terminate the capture prior + OMX_BOOL bFrameLimited; /**< If true then terminate capture after the port emits the + * specified number of frames (otherwise the port does not + * terminate the capture until instructed to do so by the client). + * Even if set, the client may manually terminate the capture prior * to reaching the limit. */ OMX_U32 nFrameLimit; /**< Limit on number of frames emitted during a capture (only * valid if bFrameLimited is set). */ } OMX_CONFIG_CAPTUREMODETYPE; typedef enum OMX_METERINGTYPE { - + OMX_MeteringModeAverage, /**< Center-weighted average metering. */ OMX_MeteringModeSpot, /**< Spot (partial) metering. */ OMX_MeteringModeMatrix, /**< Matrix or evaluative metering. */ - - OMX_MeteringKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + + OMX_MeteringKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_MeteringVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_EVModeMax = 0x7fffffff } OMX_METERINGTYPE; - + typedef struct OMX_CONFIG_EXPOSUREVALUETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; @@ -843,14 +850,14 @@ typedef struct OMX_CONFIG_EXPOSUREVALUETYPE { OMX_S32 xEVCompensation; /**< Fixed point value stored as Q16 */ OMX_U32 nApertureFNumber; /**< e.g. nApertureFNumber = 2 implies "f/2" - Q16 format */ OMX_BOOL bAutoAperture; /**< Whether aperture number is defined automatically */ - OMX_U32 nShutterSpeedMsec; /**< Shutterspeed in milliseconds */ - OMX_BOOL bAutoShutterSpeed; /**< Whether shutter speed is defined automatically */ + OMX_U32 nShutterSpeedMsec; /**< Shutterspeed in milliseconds */ + OMX_BOOL bAutoShutterSpeed; /**< Whether shutter speed is defined automatically */ OMX_U32 nSensitivity; /**< e.g. nSensitivity = 100 implies "ISO 100" */ OMX_BOOL bAutoSensitivity; /**< Whether sensitivity is defined automatically */ } OMX_CONFIG_EXPOSUREVALUETYPE; -/** - * Focus region configuration +/** + * Focus region configuration * * STRUCT MEMBERS: * nSize : Size of the structure in bytes @@ -881,8 +888,8 @@ typedef struct OMX_CONFIG_FOCUSREGIONTYPE { OMX_BOOL bBottomRight; } OMX_CONFIG_FOCUSREGIONTYPE; -/** - * Focus Status type +/** + * Focus Status type */ typedef enum OMX_FOCUSSTATUSTYPE { OMX_FocusStatusOff = 0, @@ -890,13 +897,13 @@ typedef enum OMX_FOCUSSTATUSTYPE { OMX_FocusStatusReached, OMX_FocusStatusUnableToReach, OMX_FocusStatusLost, - OMX_FocusStatusKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_FocusStatusKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_FocusStatusVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_FocusStatusMax = 0x7FFFFFFF } OMX_FOCUSSTATUSTYPE; -/** - * Focus status configuration +/** + * Focus status configuration * * STRUCT MEMBERS: * nSize : Size of the structure in bytes diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 1dc6cd2cf751..986fc7e37164 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -55,6 +55,9 @@ void SurfaceTextureClient::init() { mQueryWidth = 0; mQueryHeight = 0; mQueryFormat = 0; + mDefaultWidth = 0; + mDefaultHeight = 0; + mTransformHint = 0; mConnectedToCpu = false; } diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 8b1caeeedf59..886c05c64c07 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -883,7 +883,6 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) /////////////////////////////////////////////////////////////////////////////// DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE) { - mDisplayList = NULL; } DisplayListRenderer::~DisplayListRenderer() { @@ -923,13 +922,13 @@ void DisplayListRenderer::reset() { // Operations /////////////////////////////////////////////////////////////////////////////// -DisplayList* DisplayListRenderer::getDisplayList() { - if (mDisplayList == NULL) { - mDisplayList = new DisplayList(*this); +DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) { + if (!displayList) { + displayList = new DisplayList(*this); } else { - mDisplayList->initFromDisplayListRenderer(*this, true); + displayList->initFromDisplayListRenderer(*this, true); } - return mDisplayList; + return displayList; } void DisplayListRenderer::setViewport(int width, int height) { diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index b83259f82450..81576313c15f 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -217,7 +217,7 @@ public: DisplayListRenderer(); ~DisplayListRenderer(); - DisplayList* getDisplayList(); + DisplayList* getDisplayList(DisplayList* displayList); void setViewport(int width, int height); void prepareDirty(float left, float top, float right, float bottom, bool opaque); @@ -474,8 +474,6 @@ private: SkWriter32 mWriter; - DisplayList *mDisplayList; - int mRestoreSaveCount; friend class DisplayList; diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 412552ec8eca..0e8ae619fc5c 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -310,35 +310,21 @@ int FramebufferNativeWindow::perform(ANativeWindow* window, int operation, ...) { switch (operation) { - case NATIVE_WINDOW_SET_USAGE: - // TODO: we should implement this - return NO_ERROR; case NATIVE_WINDOW_CONNECT: - // TODO: we should implement this - return NO_ERROR; case NATIVE_WINDOW_DISCONNECT: - // TODO: we should implement this + case NATIVE_WINDOW_SET_USAGE: + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: + // TODO: we should implement these return NO_ERROR; + case NATIVE_WINDOW_LOCK: - return INVALID_OPERATION; case NATIVE_WINDOW_UNLOCK_AND_POST: - return INVALID_OPERATION; case NATIVE_WINDOW_SET_CROP: - return INVALID_OPERATION; case NATIVE_WINDOW_SET_BUFFER_COUNT: - // TODO: we should implement this - return INVALID_OPERATION; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - return INVALID_OPERATION; - case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: - return INVALID_OPERATION; case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - return INVALID_OPERATION; - case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: - return INVALID_OPERATION; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - // TODO: we should implement this - return NO_ERROR; case NATIVE_WINDOW_SET_SCALING_MODE: return INVALID_OPERATION; } diff --git a/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml b/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml index d29e4959b93d..a354336e4a2c 100644 --- a/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml +++ b/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml @@ -43,6 +43,7 @@ android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/compat_mode_help_diagram" + android:contentDescription="@string/accessibility_compatibility_zoom_example" /> <RelativeLayout android:orientation="horizontal" @@ -61,6 +62,7 @@ android:layout_alignParentRight="true" android:layout_centerVertical="true" android:src="@drawable/compat_mode_help_icon" + android:contentDescription="@string/accessibility_compatibility_zoom_button" /> <TextView android:id="@+id/explanation" diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml index d9f3f2324499..a2a64738d029 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar.xml @@ -49,6 +49,7 @@ android:src="@drawable/ic_sysbar_back" android:layout_alignParentLeft="true" systemui:keyCode="4" + android:contentDescription="@string/accessibility_back" /> <LinearLayout android:id="@+id/navigationArea" @@ -62,11 +63,13 @@ android:layout_height="match_parent" android:src="@drawable/ic_sysbar_home" systemui:keyCode="3" + android:contentDescription="@string/accessibility_home" /> <ImageView android:id="@+id/recent_apps" android:layout_width="80dip" android:layout_height="match_parent" android:src="@drawable/ic_sysbar_recent" + android:contentDescription="@string/accessibility_menu" /> <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu" android:layout_width="80dip" @@ -74,6 +77,7 @@ android:src="@drawable/ic_sysbar_menu" systemui:keyCode="82" android:visibility="invisible" + android:contentDescription="@string/accessibility_menu" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml index 3fef7e078cac..41a20fb039c9 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml @@ -53,7 +53,8 @@ android:id="@+id/item_icon" android:layout_width="@android:dimen/app_icon_size" android:layout_height="wrap_content" - android:scaleType="fitCenter" /> + android:scaleType="fitCenter" + android:contentDescription="@null" /> <LinearLayout android:orientation="vertical" android:layout_width="0px" @@ -94,7 +95,8 @@ android:visibility="visible" android:clickable="true" android:focusable="true" - android:background="?android:attr/selectableItemBackground" /> + android:background="?android:attr/selectableItemBackground" + android:contentDescription="@string/accessibility_settings_button" /> </LinearLayout> <View android:layout_width="match_parent" 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 fecfe7f1ae1b..1e3099dc3571 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml @@ -16,7 +16,7 @@ --> <!-- notification icons & panel access --> -<LinearLayout +<com.android.systemui.statusbar.tablet.NotificationArea xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/notificationArea" @@ -40,6 +40,7 @@ android:layout_marginLeft="8dip" android:src="@drawable/ic_sysbar_ime_default" android:visibility="gone" + android:contentDescription="@string/accessibility_ime_switch_button" /> <com.android.systemui.statusbar.policy.CompatModeButton @@ -49,6 +50,7 @@ android:layout_marginLeft="8dip" android:src="@drawable/ic_sysbar_zoom" android:visibility="gone" + android:contentDescription="@string/accessibility_compatibility_zoom_button" /> <com.android.systemui.statusbar.tablet.NotificationIconArea @@ -152,4 +154,4 @@ /> </LinearLayout> </LinearLayout> -</LinearLayout> +</com.android.systemui.statusbar.tablet.NotificationArea> diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml index 543f4eda576a..bbb2bc65dfbb 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml @@ -14,15 +14,17 @@ limitations under the License. --> -<RelativeLayout +<com.android.systemui.statusbar.tablet.NotificationPanelTitle xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/title_area" - android:layout_width="0dp" - android:layout_height="0dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" android:orientation="vertical" android:background="@drawable/notify_panel_clock_bg" > + <LinearLayout android:id="@+id/icons" android:layout_width="wrap_content" @@ -34,6 +36,7 @@ android:layout_marginTop="16dp" android:layout_marginBottom="16dp" > + <ImageView android:id="@+id/bluetooth" android:layout_height="32dp" @@ -41,6 +44,7 @@ android:scaleType="centerInside" android:baseline="22dp" android:visibility="gone" + android:contentDescription="@null" /> <FrameLayout @@ -49,21 +53,28 @@ android:layout_width="32dp" android:layout_marginRight="4dp" > + <ImageView android:id="@+id/network_signal" android:layout_height="match_parent" android:layout_width="match_parent" + android:contentDescription="@null" /> + <ImageView android:id="@+id/network_type" android:layout_height="match_parent" android:layout_width="match_parent" + android:contentDescription="@null" /> + <ImageView android:id="@+id/network_direction" android:layout_height="match_parent" android:layout_width="match_parent" + android:contentDescription="@null" /> + </FrameLayout> <TextView @@ -86,6 +97,7 @@ android:layout_toRightOf="@id/network_text" android:layout_alignBaseline="@id/network_signal" android:baseline="22dp" + android:contentDescription="@null" /> <TextView @@ -110,6 +122,7 @@ android:paddingRight="16dp" android:src="@drawable/ic_sysbar_quicksettings" android:baseline="21dp" + android:contentDescription="@string/accessibility_settings_button" /> <ImageView @@ -122,6 +135,7 @@ android:src="@drawable/ic_notification_open" android:baseline="21dp" android:visibility="invisible" + android:contentDescription="@string/accessibility_notifications_button" /> <View @@ -138,7 +152,7 @@ <com.android.systemui.statusbar.tablet.HoloClock android:id="@+id/clock" android:layout_height="wrap_content" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_alignParentRight="true" android:layout_above="@id/title_divider" android:layout_marginRight="6dip" @@ -164,19 +178,11 @@ android:id="@+id/date" style="@style/StatusBarNotificationText" android:layout_height="wrap_content" - android:layout_width="120dp" + android:layout_width="wrap_content" android:layout_alignBottom="@id/clock" android:layout_alignParentLeft="true" android:gravity="left" android:layout_marginLeft="32dp" /> - <view - class="com.android.systemui.statusbar.tablet.NotificationPanel$ModeToggle" - android:id="@+id/mode_toggle" - android:background="@null" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clickable="true" - /> -</RelativeLayout> +</com.android.systemui.statusbar.tablet.NotificationPanelTitle> diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml index 51e7d97ef1ec..5d7e8de463d4 100644 --- a/packages/SystemUI/res/layout/navigation_bar.xml +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -54,6 +54,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" + android:contentDescription="@string/accessibility_back" /> <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home" android:layout_width="80dp" @@ -66,6 +67,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" + android:contentDescription="@string/accessibility_home" /> <ImageView android:id="@+id/recent_apps" android:layout_width="80dp" @@ -80,6 +82,7 @@ systemui:keyCode="82" android:layout_weight="0" android:visibility="invisible" + android:contentDescription="@string/accessibility_menu" /> </LinearLayout> @@ -124,6 +127,7 @@ android:layout_height="match_parent" android:layout_width="match_parent" android:layout_weight="1" + android:contentDescription="@string/accessibility_menu" /> <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home" android:layout_height="80dp" @@ -131,11 +135,13 @@ android:src="@drawable/ic_sysbar_home_default_land" systemui:keyCode="3" android:layout_weight="0" + android:contentDescription="@string/accessibility_home" /> <View android:layout_height="match_parent" android:layout_width="match_parent" android:layout_weight="1" + android:contentDescription="@string/accessibility_back" /> <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back" android:layout_height="80dp" @@ -148,6 +154,7 @@ android:layout_height="40dp" android:layout_width="match_parent" android:layout_weight="0" + android:contentDescription="@string/accessibility_menu" /> </LinearLayout> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 01cf2dcf4a6f..082dab312aeb 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -169,4 +169,135 @@ <string name="screenshot_saving_toast">Screenshot saved to Gallery</string> <!-- toast message displayed when we fail to take a screenshot. --> <string name="screenshot_failed_toast">Could not save screenshot</string> + + <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] --> + <string name="usb_preference_title">USB file transfer options</string> + <!-- Label for the MTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] --> + <string name="use_mtp_button_title">Mount as a media player (MTP)</string> + <!-- Label for the PTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] --> + <string name="use_ptp_button_title">Mount as a camera (PTP)</string> + <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] --> + <string name="installer_cd_button_title">Install Android File Transfer application for Mac</string> + + <!-- Content description of the back button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_back">Back</string> + <!-- Content description of the home button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_home">Home</string> + <!-- Content description of the menu button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_menu">Menu</string> + + <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_ime_switch_button">Switch input method button.</string> + <!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string> + + <!-- Content description of picture of the compatibility zoom example for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_compatibility_zoom_example">Zoom smaller to larger screen.</string> + + <!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_bluetooth_connected">Bluetooth connected.</string> + <!-- Content description of the bluetooth icon when connecting for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_bluetooth_disconnected">Bluetooth disconnected.</string> + + <!-- Content description of the battery when no battery for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_no_battery">No battery.</string> + <!-- Content description of the battery when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_battery_one_bar">Battery one bar.</string> + <!-- Content description of the battery when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_battery_two_bars">Battery two bars.</string> + <!-- Content description of the battery when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_battery_three_bars">Battery three bars.</string> + <!-- Content description of the battery when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_battery_full">Battery full.</string> + + <!-- Content description of the phone signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_no_phone">No phone.</string> + <!-- Content description of the phone signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_phone_one_bar">Phone one bar.</string> + <!-- Content description of the phone signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_phone_two_bars">Phone two bars.</string> + <!-- Content description of the phone signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_phone_three_bars">Phone three bars.</string> + <!-- Content description of the phone signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_phone_signal_full">Phone signal full.</string> + + <!-- Content description of the data signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_no_data">No data.</string> + <!-- Content description of the data signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_one_bar">Data one bar.</string> + <!-- Content description of the data signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_two_bars">Data two bars.</string> + <!-- Content description of the data signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_three_bars">Data three bars.</string> + <!-- Content description of the data signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_signal_full">Data signal full.</string> + + <!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_no_wifi">No WiFi.</string> + <!-- Content description of the WIFI signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_wifi_one_bar">WiFi one bar.</string> + <!-- Content description of the WIFI signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_wifi_two_bars">WiFi two bars.</string> + <!-- Content description of the WIFI signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_wifi_three_bars">WiFi three bars.</string> + <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_wifi_signal_full">WiFi signal full.</string> + + <!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_gprs">GPRS</string> + + <!-- Content description of the data connection type 3G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_3g">3G</string> + + <!-- Content description of the data connection type 3.5G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_3.5g">3.5G</string> + + <!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_4g">4G</string> + + <!-- Content description of the data connection type CDMA for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_cdma">CDMA</string> + + <!-- Content description of the data connection type Edge for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_edge">Edge</string> + + <!-- Content description of the data connection type WiFi for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_data_connection_wifi">WiFi</string> + + <!-- Content description of the data connection with no SIM for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_no_sim">No SIM.</string> + + <!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_bluetooth_tether">Bluetooth tethering.</string> + + <!-- Content description of the airplane mode icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_airplane_mode">Airplane mode.</string> + + <!-- Content description of the battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_battery_level">Battery <xliff:g id="number">%d</xliff:g> percent.</string> + + <!-- Content description of the button for showing a settings panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_settings_button">Settings button.</string> + + <!-- Content description of the button for showing a notifications panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_notifications_button">Notifications button.</string> + + <!-- Content description of the button for removing a notification in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_remove_notification">Remove notification.</string> + + <!-- Content description of the enabled GPS icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_gps_enabled">GPS enabled.</string> + + <!-- Content description of the acquiring GPS icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_gps_acquiring">GPS acquiring.</string> + + <!-- Content description of the TeleTypewriter(TTY) enabled icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_tty_enabled">TeleTypewriter enabled.</string> + + <!-- Content description of the ringer vibrate icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_ringer_vibrate">Ringer vibrate.</string> + + <!-- Content description of the ringer silent icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_ringer_silent">Ringer silent.</string> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index bc0a508c06a7..ea544456430d 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -22,7 +22,6 @@ import java.util.List; import android.animation.Animator; import android.animation.LayoutTransition; import android.app.ActivityManager; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -48,6 +47,7 @@ import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; @@ -112,7 +112,7 @@ public class RecentsPanelView extends RelativeLayout position = _pos; packageName = _packageName; } - }; + } private final class OnLongClickDelegate implements View.OnLongClickListener { View mOtherView; @@ -252,6 +252,19 @@ public class RecentsPanelView extends RelativeLayout mChoreo.setPanelHeight(mRecentsContainer.getHeight()); } + @Override + public boolean dispatchHoverEvent(MotionEvent event) { + // Ignore hover events outside of this panel bounds since such events + // generate spurious accessibility events with the panel content when + // tapping outside of it, thus confusing the user. + final int x = (int) event.getX(); + final int y = (int) event.getY(); + if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { + return super.dispatchHoverEvent(event); + } + return true; + } + /** * Whether the panel is showing, or, if it's animating, whether it will be * when the animation is done. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java index 64ec0633810c..641977756647 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java @@ -18,8 +18,8 @@ package com.android.systemui.statusbar; import android.content.Context; import android.util.AttributeSet; -import android.util.Slog; -import android.view.MotionEvent; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; public class LatestItemView extends FrameLayout { @@ -27,7 +27,22 @@ public class LatestItemView extends FrameLayout { super(context, attrs); } + @Override public void setOnClickListener(OnClickListener l) { super.setOnClickListener(l); } + + @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (super.onRequestSendAccessibilityEvent(child, event)) { + // Add a record for the entire layout since its content is somehow small. + // The event comes from a leaf view that is interacted with. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index d9d9c06061a3..be4b39539cdb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import android.app.Notification; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; @@ -23,11 +24,11 @@ import android.graphics.drawable.Drawable; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; +import android.text.TextUtils; import android.util.Slog; import android.util.Log; -import android.view.View; import android.view.ViewDebug; -import android.widget.FrameLayout; +import android.view.accessibility.AccessibilityEvent; import java.text.NumberFormat; @@ -45,8 +46,9 @@ public class StatusBarIconView extends AnimatedImageView { private int mNumberX; private int mNumberY; private String mNumberText; + private Notification mNotification; - public StatusBarIconView(Context context, String slot) { + public StatusBarIconView(Context context, String slot, Notification notification) { super(context); final Resources res = context.getResources(); mSlot = slot; @@ -54,6 +56,8 @@ public class StatusBarIconView extends AnimatedImageView { mNumberPain.setTextAlign(Paint.Align.CENTER); mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color)); mNumberPain.setAntiAlias(true); + mNotification = notification; + setContentDescription(notification); } private static boolean streq(String a, String b) { @@ -83,6 +87,7 @@ public class StatusBarIconView extends AnimatedImageView { final boolean numberEquals = mIcon != null && mIcon.number == icon.number; mIcon = icon.clone(); + setContentDescription(icon.contentDescription); if (!iconEquals) { Drawable drawable = getIcon(icon); if (drawable == null) { @@ -159,6 +164,15 @@ public class StatusBarIconView extends AnimatedImageView { return mIcon; } + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + if (mNotification != null) { + event.setParcelableData(mNotification); + } + } + + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (mNumberBackground != null) { @@ -166,6 +180,7 @@ public class StatusBarIconView extends AnimatedImageView { } } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -175,6 +190,7 @@ public class StatusBarIconView extends AnimatedImageView { } } + @Override protected void debug(int depth) { super.debug(depth); Log.d("View", debugIndent(depth) + "slot=" + mSlot); @@ -213,4 +229,13 @@ public class StatusBarIconView extends AnimatedImageView { mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2); mNumberBackground.setBounds(w-dw, h-dh, w, h); } + + private void setContentDescription(Notification notification) { + if (notification != null) { + CharSequence tickerText = notification.tickerText; + if (!TextUtils.isEmpty(tickerText)) { + setContentDescription(tickerText); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java index e1d17a891607..f6aa159555fc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java @@ -33,7 +33,8 @@ public class IconMerger extends LinearLayout { private int mIconSize; private StatusBarIconView mMoreView; - private StatusBarIcon mMoreIcon = new StatusBarIcon(null, R.drawable.stat_notify_more, 0); + private StatusBarIcon mMoreIcon = new StatusBarIcon(null, R.drawable.stat_notify_more, 0, 0, + null); public IconMerger(Context context, AttributeSet attrs) { super(context, attrs); @@ -41,7 +42,7 @@ public class IconMerger extends LinearLayout { mIconSize = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); - mMoreView = new StatusBarIconView(context, "more"); + mMoreView = new StatusBarIconView(context, "more", null); mMoreView.set(mMoreIcon); addView(mMoreView, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize)); } 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 f4c4bbcf935e..b93ad684311b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -472,7 +472,7 @@ public class PhoneStatusBar extends StatusBar { public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + " icon=" + icon); - StatusBarIconView view = new StatusBarIconView(mContext, slot); + StatusBarIconView view = new StatusBarIconView(mContext, slot, null); view.set(icon); mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); } @@ -607,7 +607,7 @@ public class PhoneStatusBar extends StatusBar { // Update the icon. final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon, notification.notification.iconLevel, - notification.notification.number); + notification.notification.number, notification.notification.tickerText); if (!oldEntry.icon.set(ic)) { handleNotificationError(key, notification, "Couldn't update icon: " + ic); return; @@ -765,9 +765,11 @@ public class PhoneStatusBar extends StatusBar { final View expanded = views[2]; // Construct the icon. final StatusBarIconView iconView = new StatusBarIconView(mContext, - notification.pkg + "/0x" + Integer.toHexString(notification.id)); + notification.pkg + "/0x" + Integer.toHexString(notification.id), + notification.notification); final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon, - notification.notification.iconLevel, notification.notification.number); + notification.notification.iconLevel, notification.notification.number, + notification.notification.tickerText); if (!iconView.set(ic)) { handleNotificationError(key, notification, "Coulding create icon: " + ic); return null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index af5c72d92cdc..7b5098534915 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -18,25 +18,17 @@ package com.android.systemui.statusbar.phone; import android.app.StatusBarManager; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothPbap; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.TypedArray; -import android.graphics.PixelFormat; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.Uri; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Handler; -import android.os.Message; import android.os.RemoteException; import android.os.storage.StorageManager; import android.provider.Settings; @@ -44,18 +36,7 @@ import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; -import android.text.format.DateFormat; -import android.text.style.CharacterStyle; -import android.text.style.RelativeSizeSpan; -import android.text.style.ForegroundColorSpan; -import android.text.style.StyleSpan; -import android.text.Spannable; -import android.text.SpannableStringBuilder; import android.util.Slog; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.IccCard; @@ -63,7 +44,6 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.EriInfo; import com.android.internal.telephony.cdma.TtyIntent; import com.android.server.am.BatteryStatsService; - import com.android.systemui.R; /** @@ -447,6 +427,32 @@ public class PhoneStatusBarPolicy { R.drawable.stat_sys_data_fully_inandout_1x } }; + // Accessibility; + + private static final int[] sPhoneSignalStrength = { + R.string.accessibility_no_phone, + R.string.accessibility_phone_one_bar, + R.string.accessibility_phone_two_bars, + R.string.accessibility_phone_three_bars, + R.string.accessibility_phone_signal_full + }; + + private static final int[] sDataConnectionStrength = { + R.string.accessibility_no_data, + R.string.accessibility_data_one_bar, + R.string.accessibility_data_two_bars, + R.string.accessibility_data_three_bars, + R.string.accessibility_data_signal_full + }; + + private static final int[] sWifiConnectionStrength = { + R.string.accessibility_no_wifi, + R.string.accessibility_wifi_one_bar, + R.string.accessibility_wifi_two_bars, + R.string.accessibility_wifi_three_bars, + R.string.accessibility_wifi_signal_full + }; + // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. IccCard.State mSimState = IccCard.State.READY; @@ -546,12 +552,13 @@ public class PhoneStatusBarPolicy { new com.android.systemui.usb.StorageNotification(context)); // battery - mService.setIcon("battery", com.android.internal.R.drawable.stat_sys_battery_unknown, 0); + mService.setIcon("battery", com.android.internal.R.drawable.stat_sys_battery_unknown, 0, + null); // phone_signal mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); mPhoneSignalIconId = R.drawable.stat_sys_signal_null; - mService.setIcon("phone_signal", mPhoneSignalIconId, 0); + mService.setIcon("phone_signal", mPhoneSignalIconId, 0, null); // register for phone state notifications. ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)) @@ -563,24 +570,24 @@ public class PhoneStatusBarPolicy { | PhoneStateListener.LISTEN_DATA_ACTIVITY); // data_connection - mService.setIcon("data_connection", R.drawable.stat_sys_data_connected_g, 0); + mService.setIcon("data_connection", R.drawable.stat_sys_data_connected_g, 0, null); mService.setIconVisibility("data_connection", false); // wifi - mService.setIcon("wifi", sWifiSignalImages[0][0], 0); + mService.setIcon("wifi", sWifiSignalImages[0][0], 0, null); mService.setIconVisibility("wifi", false); // wifi will get updated by the sticky intents // TTY status - mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0); + mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0, null); mService.setIconVisibility("tty", false); // Cdma Roaming Indicator, ERI - mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0); + mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0, null); mService.setIconVisibility("cdma_eri", false); // bluetooth status - mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0); + mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0, null); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { mBluetoothEnabled = adapter.isEnabled(); @@ -590,21 +597,23 @@ public class PhoneStatusBarPolicy { mService.setIconVisibility("bluetooth", mBluetoothEnabled); // Gps status - mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0); + mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0, null); mService.setIconVisibility("gps", false); // Alarm clock - mService.setIcon("alarm_clock", R.drawable.stat_notify_alarm, 0); + mService.setIcon("alarm_clock", R.drawable.stat_notify_alarm, 0, null); mService.setIconVisibility("alarm_clock", false); // Sync state - mService.setIcon("sync_active", com.android.internal.R.drawable.stat_notify_sync_anim0, 0); - mService.setIcon("sync_failing", com.android.internal.R.drawable.stat_notify_sync_error, 0); + mService.setIcon("sync_active", com.android.internal.R.drawable.stat_notify_sync_anim0, + 0, null); + mService.setIcon("sync_failing", com.android.internal.R.drawable.stat_notify_sync_error, + 0, null); mService.setIconVisibility("sync_active", false); mService.setIconVisibility("sync_failing", false); // volume - mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0); + mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null); mService.setIconVisibility("volume", false); updateVolume(); @@ -655,7 +664,8 @@ public class PhoneStatusBarPolicy { private final void updateBattery(Intent intent) { final int id = intent.getIntExtra("icon-small", 0); int level = intent.getIntExtra("level", 0); - mService.setIcon("battery", id, level); + String contentDescription = mContext.getString(R.string.accessibility_battery_level, level); + mService.setIcon("battery", id, level, contentDescription); } private void updateConnectivity(Intent intent) { @@ -677,12 +687,16 @@ public class PhoneStatusBarPolicy { if (info.isConnected()) { mIsWifiConnected = true; int iconId; + String contentDescription = null; if (mLastWifiSignalLevel == -1) { iconId = sWifiSignalImages[mInetCondition][0]; + contentDescription = mContext.getString(sWifiConnectionStrength[0]); } else { iconId = sWifiSignalImages[mInetCondition][mLastWifiSignalLevel]; - } - mService.setIcon("wifi", iconId, 0); + contentDescription = mContext.getString( + sWifiConnectionStrength[mLastWifiSignalLevel]); + } + mService.setIcon("wifi", iconId, 0, contentDescription); // Show the icon since wi-fi is connected mService.setIconVisibility("wifi", true); } else { @@ -690,7 +704,8 @@ public class PhoneStatusBarPolicy { mIsWifiConnected = false; int iconId = sWifiSignalImages[0][0]; - mService.setIcon("wifi", iconId, 0); + String contentDescription = mContext.getString(R.string.accessibility_no_wifi); + mService.setIcon("wifi", iconId, 0, contentDescription); // Hide the icon since we're not connected mService.setIconVisibility("wifi", false); } @@ -781,6 +796,7 @@ public class PhoneStatusBarPolicy { private final void updateSignalStrength() { int[] iconList; + String contentDescription = null; // Display signal strength while in "emergency calls only" mode if (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly())) { @@ -788,10 +804,12 @@ public class PhoneStatusBarPolicy { if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1) { mPhoneSignalIconId = R.drawable.stat_sys_signal_flightmode; + contentDescription = mContext.getString(R.string.accessibility_airplane_mode); } else { mPhoneSignalIconId = R.drawable.stat_sys_signal_null; + contentDescription = mContext.getString(R.string.accessibility_no_phone); } - mService.setIcon("phone_signal", mPhoneSignalIconId, 0); + mService.setIcon("phone_signal", mPhoneSignalIconId, 0, contentDescription); return; } @@ -805,8 +823,11 @@ public class PhoneStatusBarPolicy { } else { iconList = sSignalImages[mInetCondition]; } - mPhoneSignalIconId = iconList[mSignalStrength.getLevel()]; - mService.setIcon("phone_signal", mPhoneSignalIconId, 0); + + final int signalLevel = mSignalStrength.getLevel(); + mPhoneSignalIconId = iconList[signalLevel]; + contentDescription = mContext.getString(sPhoneSignalStrength[signalLevel]); + mService.setIcon("phone_signal", mPhoneSignalIconId, 0, contentDescription); } private final void updateDataNetType(int net) { @@ -850,6 +871,7 @@ public class PhoneStatusBarPolicy { private final void updateDataIcon() { int iconId; + String contentDescription = null; boolean visible = true; if (!isCdma()) { @@ -870,13 +892,15 @@ public class PhoneStatusBarPolicy { iconId = mDataIconList[0]; break; } - mService.setIcon("data_connection", iconId, 0); + contentDescription = mContext.getString(sDataConnectionStrength[mDataActivity]); + mService.setIcon("data_connection", iconId, 0, contentDescription); } else { visible = false; } } else { iconId = R.drawable.stat_sys_no_sim; - mService.setIcon("data_connection", iconId, 0); + contentDescription = mContext.getString(R.string.accessibility_no_sim); + mService.setIcon("data_connection", iconId, 0, contentDescription); } } else { // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT @@ -896,7 +920,7 @@ public class PhoneStatusBarPolicy { iconId = mDataIconList[0]; break; } - mService.setIcon("data_connection", iconId, 0); + mService.setIcon("data_connection", iconId, 0, null); } else { visible = false; } @@ -921,12 +945,19 @@ public class PhoneStatusBarPolicy { final int ringerMode = audioManager.getRingerMode(); final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || ringerMode == AudioManager.RINGER_MODE_VIBRATE; - final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER) - ? R.drawable.stat_sys_ringer_vibrate - : R.drawable.stat_sys_ringer_silent; + + final int iconId; + String contentDescription = null; + if (audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) { + iconId = R.drawable.stat_sys_ringer_vibrate; + contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate); + } else { + iconId = R.drawable.stat_sys_ringer_silent; + contentDescription = mContext.getString(R.string.accessibility_ringer_silent); + } if (visible) { - mService.setIcon("volume", iconId, 0); + mService.setIcon("volume", iconId, 0, contentDescription); } if (visible != mVolumeVisible) { mService.setIconVisibility("volume", visible); @@ -936,6 +967,7 @@ public class PhoneStatusBarPolicy { private final void updateBluetooth(Intent intent) { int iconId = R.drawable.stat_sys_data_bluetooth; + String contentDescription = null; String action = intent.getAction(); if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); @@ -945,12 +977,16 @@ public class PhoneStatusBarPolicy { BluetoothAdapter.STATE_DISCONNECTED); if (state == BluetoothAdapter.STATE_CONNECTED) { iconId = R.drawable.stat_sys_data_bluetooth_connected; + contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected); + } else { + contentDescription = mContext.getString( + R.string.accessibility_bluetooth_disconnected); } } else { return; } - mService.setIcon("bluetooth", iconId, 0); + mService.setIcon("bluetooth", iconId, 0, contentDescription); mService.setIconVisibility("bluetooth", mBluetoothEnabled); } @@ -974,6 +1010,7 @@ public class PhoneStatusBarPolicy { } } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { int iconId; + String contentDescription = null; final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, sWifiSignalImages[0].length); @@ -981,10 +1018,13 @@ public class PhoneStatusBarPolicy { mLastWifiSignalLevel = newSignalLevel; if (mIsWifiConnected) { iconId = sWifiSignalImages[mInetCondition][newSignalLevel]; + contentDescription = mContext.getString( + sWifiConnectionStrength[newSignalLevel]); } else { iconId = sWifiTemporarilyNotConnectedImage; + contentDescription = mContext.getString(R.string.accessibility_no_wifi); } - mService.setIcon("wifi", iconId, 0); + mService.setIcon("wifi", iconId, 0, contentDescription); } } } @@ -995,14 +1035,16 @@ public class PhoneStatusBarPolicy { if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) { // GPS is getting fixes - mService.setIcon("gps", com.android.internal.R.drawable.stat_sys_gps_on, 0); + mService.setIcon("gps", com.android.internal.R.drawable.stat_sys_gps_on, 0, + mContext.getString(R.string.accessibility_gps_enabled)); mService.setIconVisibility("gps", true); } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) { // GPS is off mService.setIconVisibility("gps", false); } else { // GPS is on, but not receiving fixes - mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0); + mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0, + mContext.getString(R.string.accessibility_gps_acquiring)); mService.setIconVisibility("gps", true); } } @@ -1016,7 +1058,8 @@ public class PhoneStatusBarPolicy { if (enabled) { // TTY is on if (false) Slog.v(TAG, "updateTTY: set TTY on"); - mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0); + mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0, + mContext.getString(R.string.accessibility_tty_enabled)); mService.setIconVisibility("tty", true); } else { // TTY is off @@ -1058,15 +1101,15 @@ public class PhoneStatusBarPolicy { switch (iconMode) { case EriInfo.ROAMING_ICON_MODE_NORMAL: - mService.setIcon("cdma_eri", iconList[iconIndex], 0); + mService.setIcon("cdma_eri", iconList[iconIndex], 0, null); mService.setIconVisibility("cdma_eri", true); break; case EriInfo.ROAMING_ICON_MODE_FLASH: - mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_flash, 0); + mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_flash, 0, null); mService.setIconVisibility("cdma_eri", true); break; } - mService.setIcon("phone_signal", mPhoneSignalIconId, 0); + mService.setIcon("phone_signal", mPhoneSignalIconId, 0, null); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 84c524a496d8..c2390e851313 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -26,6 +26,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import com.android.systemui.R; @@ -203,5 +204,19 @@ public class PhoneStatusBarView extends FrameLayout { return mService.interceptTouchEvent(event) ? true : super.onInterceptTouchEvent(event); } -} + @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (super.onRequestSendAccessibilityEvent(child, event)) { + // The status bar is very small so augment the view that the user is touching + // with the content of the status bar a whole. This way an accessibility service + // may announce the current item as well as the entire content if appropriate. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java index 8ee12deb29a8..e76fe517e0e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java @@ -183,7 +183,8 @@ public abstract class Ticker { } final Drawable icon = StatusBarIconView.getIcon(mContext, - new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0)); + new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0, + n.notification.tickerText)); final Segment newSegment = new Segment(n, icon, n.notification.tickerText); // If there's already a notification schedule for this package and id, remove it. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java new file mode 100644 index 000000000000..13fb03e6c677 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java @@ -0,0 +1,37 @@ +// Copyright 2011 Google Inc. All Rights Reserved. + +package com.android.systemui.statusbar.policy; + +import com.android.systemui.R; + +/** + * Content descriptions for accessibility support. + */ +public class AccessibilityContentDescriptions { + + private AccessibilityContentDescriptions() {} + + static final int[] PHONE_SIGNAL_STRENGTH = { + R.string.accessibility_no_phone, + R.string.accessibility_phone_one_bar, + R.string.accessibility_phone_two_bars, + R.string.accessibility_phone_three_bars, + R.string.accessibility_phone_signal_full + }; + + static final int[] DATA_CONNECTION_STRENGTH = { + R.string.accessibility_no_data, + R.string.accessibility_data_one_bar, + R.string.accessibility_data_two_bars, + R.string.accessibility_data_three_bars, + R.string.accessibility_data_signal_full + }; + + static final int[] WIFI_CONNECTION_STRENGTH = { + R.string.accessibility_no_wifi, + R.string.accessibility_wifi_one_bar, + R.string.accessibility_wifi_two_bars, + R.string.accessibility_wifi_three_bars, + R.string.accessibility_wifi_signal_full + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index ae2b6b2c8c24..3957c1b80ab3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -62,12 +62,15 @@ public class BatteryController extends BroadcastReceiver { ImageView v = mIconViews.get(i); v.setImageResource(icon); v.setImageLevel(level); + v.setContentDescription(mContext.getString(R.string.accessibility_battery_level, + level)); } N = mLabelViews.size(); for (int i=0; i<N; i++) { //final boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; TextView v = mLabelViews.get(i); - v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format, level)); + v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format, + level)); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java index 0525054b4aaa..c6f416f5ff8a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java @@ -19,12 +19,10 @@ package com.android.systemui.statusbar.policy; import java.util.ArrayList; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.util.Slog; import android.view.View; import android.widget.ImageView; @@ -54,26 +52,24 @@ public class BluetoothController extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { - int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); - mEnabled = state == BluetoothAdapter.STATE_ON; - } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { - int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, + int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.STATE_DISCONNECTED); - if (state == BluetoothAdapter.STATE_CONNECTED) { - mIconId = R.drawable.stat_sys_data_bluetooth_connected; - } else { - mIconId = R.drawable.stat_sys_data_bluetooth; - } - } + int contentDescriptionResId = 0; + if (state == BluetoothAdapter.STATE_CONNECTED) { + mIconId = R.drawable.stat_sys_data_bluetooth_connected; + contentDescriptionResId = R.string.accessibility_bluetooth_connected; + } else { + mIconId = R.drawable.stat_sys_data_bluetooth; + contentDescriptionResId = R.string.accessibility_bluetooth_disconnected; + } int N = mIconViews.size(); for (int i=0; i<N; i++) { ImageView v = mIconViews.get(i); v.setImageResource(mIconId); v.setVisibility(mEnabled ? View.VISIBLE : View.GONE); + v.setContentDescription(mContext.getString(contentDescriptionResId)); } } } 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 3175a99fb482..829855b697ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -28,14 +28,11 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.wifi.SupplicantState; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; @@ -87,6 +84,11 @@ public class NetworkController extends BroadcastReceiver { int mDataTypeIconId; boolean mDataActive; + String mContentDescriptionPhoneSignal; + String mContentDescriptionWifi; + String mContentDescriptionCombinedSignal; + String mContentDescriptionDataType; + // wifi final WifiManager mWifiManager; AsyncChannel mWifiChannel; @@ -366,6 +368,8 @@ public class NetworkController extends BroadcastReceiver { if (mSignalStrength == null) { mPhoneSignalIconId = R.drawable.stat_sys_signal_null; mDataSignalIconId = R.drawable.stat_sys_signal_0; // note we use 0 instead of null + mContentDescriptionPhoneSignal = mContext.getString( + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]); } else { int iconLevel; int[] iconList; @@ -385,6 +389,9 @@ public class NetworkController extends BroadcastReceiver { } } mPhoneSignalIconId = iconList[iconLevel]; + mContentDescriptionPhoneSignal = mContext.getString( + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]); + mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; } } @@ -395,14 +402,20 @@ public class NetworkController extends BroadcastReceiver { case TelephonyManager.NETWORK_TYPE_UNKNOWN: mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; mDataTypeIconId = 0; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_gprs); break; case TelephonyManager.NETWORK_TYPE_EDGE: mDataIconList = TelephonyIcons.DATA_E[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_edge; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_edge); break; case TelephonyManager.NETWORK_TYPE_UMTS: mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_3g; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); break; case TelephonyManager.NETWORK_TYPE_HSDPA: case TelephonyManager.NETWORK_TYPE_HSUPA: @@ -410,19 +423,27 @@ public class NetworkController extends BroadcastReceiver { if (mHspaDataDistinguishable) { mDataIconList = TelephonyIcons.DATA_H[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_hsdpa; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3_5g); } else { mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_3g; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); } break; case TelephonyManager.NETWORK_TYPE_CDMA: // display 1xRTT for IS95A/B mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_1x; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_cdma); break; case TelephonyManager.NETWORK_TYPE_1xRTT: mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_1x; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_cdma); break; case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through case TelephonyManager.NETWORK_TYPE_EVDO_A: @@ -430,14 +451,20 @@ public class NetworkController extends BroadcastReceiver { case TelephonyManager.NETWORK_TYPE_EHRPD: mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_3g; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); break; case TelephonyManager.NETWORK_TYPE_LTE: mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_4g; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_4g); break; default: mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; mDataTypeIconId = R.drawable.stat_sys_signal_gprs; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_gprs); break; } if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) { @@ -618,8 +645,11 @@ public class NetworkController extends BroadcastReceiver { private void updateWifiIcons() { if (mWifiConnected) { mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; + mContentDescriptionWifi = mContext.getString( + AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]); } else { mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]; + mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi); } } @@ -704,6 +734,7 @@ public class NetworkController extends BroadcastReceiver { } } combinedSignalIconId = mWifiIconId; + mContentDescriptionCombinedSignal = mContentDescriptionWifi; dataTypeIconId = 0; } else if (mDataConnected) { label = mNetworkName; @@ -723,22 +754,29 @@ public class NetworkController extends BroadcastReceiver { break; } combinedSignalIconId = mDataSignalIconId; + mContentDescriptionCombinedSignal = mContentDescriptionDataType; dataTypeIconId = mDataTypeIconId; } else if (mBluetoothTethered) { label = mContext.getString(R.string.bluetooth_tethered); combinedSignalIconId = mBluetoothTetherIconId; + mContentDescriptionCombinedSignal = mContext.getString( + R.string.accessibility_bluetooth_tether); dataTypeIconId = 0; } else if (mAirplaneMode && (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { // Only display the flight-mode icon if not in "emergency calls only" mode. label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); combinedSignalIconId = R.drawable.stat_sys_signal_flightmode; + mContentDescriptionCombinedSignal = mContext.getString( + R.string.accessibility_airplane_mode); dataTypeIconId = 0; } else { label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); // On devices without mobile radios, we want to show the wifi icon combinedSignalIconId = hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId; + mContentDescriptionCombinedSignal = hasMobileDataFeature() + ? mContentDescriptionDataType : mContentDescriptionWifi; dataTypeIconId = 0; } @@ -764,6 +802,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mPhoneSignalIconViews.get(i); v.setImageResource(mPhoneSignalIconId); + v.setContentDescription(mContentDescriptionPhoneSignal); } } @@ -774,6 +813,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mDataDirectionIconViews.get(i); v.setImageResource(mDataDirectionIconId); + v.setContentDescription(mContentDescriptionDataType); } } @@ -784,6 +824,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mWifiIconViews.get(i); v.setImageResource(mWifiIconId); + v.setContentDescription(mContentDescriptionWifi); } } @@ -794,6 +835,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mCombinedSignalIconViews.get(i); v.setImageResource(combinedSignalIconId); + v.setContentDescription(mContentDescriptionCombinedSignal); } } @@ -808,6 +850,7 @@ public class NetworkController extends BroadcastReceiver { } else { v.setVisibility(View.VISIBLE); v.setImageResource(dataTypeIconId); + v.setContentDescription(mContentDescriptionDataType); } } } @@ -826,6 +869,7 @@ public class NetworkController extends BroadcastReceiver { } else { v.setVisibility(View.VISIBLE); v.setImageResource(dataDirectionOverlayIconId); + v.setContentDescription(mContentDescriptionDataType); } } } 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 b4d2a14ecb07..d5885bb81c25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java @@ -148,6 +148,11 @@ public class NotificationRowLayout extends ViewGroup { "now sliding child %d: %s (touchY=%.1f, rowHeight=%d, count=%d)", childIdx, mSlidingChild, mInitialTouchY, mRowHeight, count)); } + + + // We need to prevent the surrounding ScrollView from intercepting us now; + // the scroll position will be locked while we swipe + requestDisallowInterceptTouchEvent(true); } } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java index c62c4ad872cf..8c4ae197d3b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java @@ -22,6 +22,7 @@ import android.content.res.TypedArray; import android.os.RemoteException; import android.util.AttributeSet; import android.util.Slog; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; @@ -90,6 +91,19 @@ public class CompatModePanel extends FrameLayout implements StatusBarPanel, return false; } + @Override + public boolean dispatchHoverEvent(MotionEvent event) { + // Ignore hover events outside of this panel bounds since such events + // generate spurious accessibility events with the panel content when + // tapping outside of it, thus confusing the user. + final int x = (int) event.getX(); + final int y = (int) event.getY(); + if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { + return super.dispatchHoverEvent(event); + } + return true; + } + public void setTrigger(View v) { mTrigger = v; } 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 339e3f3812b9..1e417acdd41c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java @@ -30,6 +30,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; +import android.view.MotionEvent; import android.view.View; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -160,6 +161,19 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, } } + @Override + public boolean dispatchHoverEvent(MotionEvent event) { + // Ignore hover events outside of this panel bounds since such events + // generate spurious accessibility events with the panel content when + // tapping outside of it, thus confusing the user. + final int x = (int) event.getX(); + final int y = (int) event.getY(); + if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { + return super.dispatchHoverEvent(event); + } + return true; + } + private void updateHardKeyboardEnabled() { if (mHardKeyboardAvailable) { final boolean checked = mHardKeyboardSwitch.isChecked(); @@ -222,6 +236,7 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, itemSubtitle.setText(imiName); } subtypeIcon.setImageDrawable(icon); + subtypeIcon.setContentDescription(itemTitle.getText()); final String settingsActivity = imi.getSettingsActivity(); if (!TextUtils.isEmpty(settingsActivity)) { settingsIcon.setOnClickListener(new View.OnClickListener() { @@ -463,4 +478,5 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, public interface OnHardKeyboardEnabledChangeListener { public void onHardKeyboardEnabledChange(boolean enabled); } + } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java new file mode 100644 index 000000000000..42bdf3d925e3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tablet; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.widget.LinearLayout; + +public class NotificationArea extends LinearLayout { + + public NotificationArea(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (super.onRequestSendAccessibilityEvent(child, event)) { + // The event is coming from a descendant like battery but append + // the content of the entire notification area so accessibility + // services can choose how to present the content to the user. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java index 64a4f160830f..a316e4b4b023 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java @@ -20,27 +20,15 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Slog; -import android.view.accessibility.AccessibilityEvent; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; -import android.widget.FrameLayout; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.RelativeLayout; -import android.widget.TextView; import com.android.systemui.R; @@ -53,8 +41,7 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, boolean mShowing; int mNotificationCount = 0; - View mTitleArea; - ModeToggle mModeToggle; + NotificationPanelTitle mTitleArea; View mSettingsButton; View mNotificationButton; View mNotificationScroller; @@ -68,48 +55,6 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, Choreographer mChoreo = new Choreographer(); - static class ModeToggle extends View { - NotificationPanel mPanel; - View mTitle; - public ModeToggle(Context context, AttributeSet attrs) { - super(context, attrs); - } - public void setPanel(NotificationPanel p) { - mPanel = p; - } - public void setTitleArea(View v) { - mTitle = v; - } - @Override - public boolean onTouchEvent(MotionEvent e) { - final int x = (int)e.getX(); - final int y = (int)e.getY(); - switch (e.getAction()) { - case MotionEvent.ACTION_DOWN: - mTitle.setPressed(true); - break; - case MotionEvent.ACTION_MOVE: - mTitle.setPressed(x >= 0 - && x < getWidth() - && y >= 0 - && y < getHeight()); - break; - case MotionEvent.ACTION_CANCEL: - mTitle.setPressed(false); - break; - case MotionEvent.ACTION_UP: - if (mTitle.isPressed()) { - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); - playSoundEffect(SoundEffectConstants.CLICK); - mPanel.swapPanels(); - mTitle.setPressed(false); - } - break; - } - return true; - } - } - public NotificationPanel(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -126,14 +71,11 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, mContentParent = (ViewGroup)findViewById(R.id.content_parent); mContentParent.bringToFront(); - mTitleArea = findViewById(R.id.title_area); - mModeToggle = (ModeToggle) findViewById(R.id.mode_toggle); - mModeToggle.setOnClickListener(this); - mModeToggle.setPanel(this); - mModeToggle.setTitleArea(mTitleArea); + mTitleArea = (NotificationPanelTitle) findViewById(R.id.title_area); + mTitleArea.setPanel(this); - mSettingsButton = (ImageView)findViewById(R.id.settings_button); - mNotificationButton = (ImageView)findViewById(R.id.notification_button); + mSettingsButton = findViewById(R.id.settings_button); + mNotificationButton = findViewById(R.id.notification_button); mNotificationScroller = findViewById(R.id.notification_scroller); mContentFrame = (ViewGroup)findViewById(R.id.content_frame); @@ -185,6 +127,19 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, } } + @Override + public boolean dispatchHoverEvent(MotionEvent event) { + // Ignore hover events outside of this panel bounds since such events + // generate spurious accessibility events with the panel content when + // tapping outside of it, thus confusing the user. + final int x = (int) event.getX(); + final int y = (int) event.getY(); + if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { + return super.dispatchHoverEvent(event); + } + return true; + } + /* @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { @@ -205,7 +160,7 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, */ public void onClick(View v) { - if (v == mModeToggle) { + if (v == mTitleArea) { swapPanels(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java new file mode 100644 index 000000000000..689bc36a4320 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tablet; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.widget.RelativeLayout; + +public class NotificationPanelTitle extends RelativeLayout implements View.OnClickListener { + private NotificationPanel mPanel; + + public NotificationPanelTitle(Context context, AttributeSet attrs) { + super(context, attrs); + setOnClickListener(this); + } + + public void setPanel(NotificationPanel p) { + mPanel = p; + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + switch (e.getAction()) { + case MotionEvent.ACTION_DOWN: + setPressed(true); + break; + case MotionEvent.ACTION_MOVE: + final int x = (int) e.getX(); + final int y = (int) e.getY(); + setPressed(x > 0 && x < getWidth() && y > 0 && y < getHeight()); + break; + case MotionEvent.ACTION_UP: + if (isPressed()) { + playSoundEffect(SoundEffectConstants.CLICK); + mPanel.swapPanels(); + setPressed(false); + } + break; + case MotionEvent.ACTION_CANCEL: + setPressed(false); + break; + } + return true; + } + + @Override + public void onClick(View v) { + if (v == this) { + mPanel.swapPanels(); + } + } + + @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (super.onRequestSendAccessibilityEvent(child, event)) { + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java index 8b682403fb29..ba2830605fce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java @@ -18,12 +18,9 @@ package com.android.systemui.statusbar.tablet; import android.content.Context; import android.util.AttributeSet; -import android.util.Slog; import android.view.MotionEvent; import android.widget.RelativeLayout; -import com.android.systemui.R; - public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel { TabletStatusBar mBar; @@ -54,5 +51,17 @@ public class NotificationPeekPanel extends RelativeLayout implements StatusBarPa mBar.resetNotificationPeekFadeTimer(); return false; } -} + @Override + public boolean dispatchHoverEvent(MotionEvent event) { + // Ignore hover events outside of this panel bounds since such events + // generate spurious accessibility events with the panel content when + // tapping outside of it, thus confusing the user. + final int x = (int) event.getX(); + final int y = (int) event.getY(); + if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { + return super.dispatchHoverEvent(event); + } + return true; + } +} 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 df09f84e5c51..13846ed1e237 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -808,7 +808,8 @@ public class TabletStatusBar extends StatusBar implements // Update the icon. final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon, notification.notification.iconLevel, - notification.notification.number); + notification.notification.number, + notification.notification.tickerText); if (!oldEntry.icon.set(ic)) { handleNotificationError(key, notification, "Couldn't update icon: " + ic); return; @@ -1012,10 +1013,7 @@ public class TabletStatusBar extends StatusBar implements mCompatModeButton.refresh(); if (mCompatModeButton.getVisibility() == View.VISIBLE) { - if (DEBUG_COMPAT_HELP - || ! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) { showCompatibilityHelp(); - } } else { hideCompatibilityHelp(); mCompatModePanel.closePanel(); @@ -1451,13 +1449,15 @@ public class TabletStatusBar extends StatusBar implements } // Construct the icon. final StatusBarIconView iconView = new StatusBarIconView(mContext, - notification.pkg + "/0x" + Integer.toHexString(notification.id)); + notification.pkg + "/0x" + Integer.toHexString(notification.id), + notification.notification); iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon, notification.notification.iconLevel, - notification.notification.number); + notification.notification.number, + notification.notification.tickerText); if (!iconView.set(ic)) { handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic); return null; @@ -1501,11 +1501,6 @@ public class TabletStatusBar extends StatusBar implements // alternate behavior in DND mode if (mNotificationDNDMode) { if (mIconLayout.getChildCount() == 0) { - final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd"); - iconView.setImageResource(R.drawable.ic_notification_dnd); - iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0); - final Notification dndNotification = new Notification.Builder(mContext) .setContentTitle(mContext.getText(R.string.notifications_off_title)) .setContentText(mContext.getText(R.string.notifications_off_text)) @@ -1513,6 +1508,12 @@ public class TabletStatusBar extends StatusBar implements .setOngoing(true) .getNotification(); + final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd", + dndNotification); + iconView.setImageResource(R.drawable.ic_notification_dnd); + iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0); + mNotificationDNDDummyEntry = new NotificationData.Entry( null, new StatusBarNotification("", 0, "", 0, 0, dndNotification), @@ -1634,19 +1635,24 @@ public class TabletStatusBar extends StatusBar implements } else { if ((sbn.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) { vetoButton.setVisibility(View.INVISIBLE); + vetoButton.setContentDescription("VETO"); } else { vetoButton.setVisibility(View.GONE); } } + vetoButton.setContentDescription(mContext.getString( + R.string.accessibility_remove_notification)); // the large icon ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon); if (sbn.notification.largeIcon != null) { largeIcon.setImageBitmap(sbn.notification.largeIcon); + largeIcon.setContentDescription(sbn.notification.tickerText); } else { largeIcon.getLayoutParams().width = 0; largeIcon.setVisibility(View.INVISIBLE); } + largeIcon.setContentDescription(sbn.notification.tickerText); // bind the click event to the content area ViewGroup content = (ViewGroup)row.findViewById(R.id.content); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java index a8f4262aff79..6045e31d3ad7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java @@ -284,7 +284,7 @@ public class TabletTicker } else if (n.tickerText != null) { group = (ViewGroup)inflater.inflate(R.layout.status_bar_ticker_compat, mWindow, false); final Drawable icon = StatusBarIconView.getIcon(mContext, - new StatusBarIcon(notification.pkg, n.icon, n.iconLevel, 0)); + new StatusBarIcon(notification.pkg, n.icon, n.iconLevel, 0, n.tickerText)); ImageView iv = (ImageView)group.findViewById(iconId); iv.setImageDrawable(icon); iv.setVisibility(View.VISIBLE); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 935f4ad0cb6d..47d34b3261de 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -35,7 +35,6 @@ import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Handler; -import android.os.IBinder; import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; @@ -43,7 +42,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; @@ -1117,8 +1115,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // Give feedback to user when secure keyguard is active and engaged if (mShowing && isSecure()) { if (!mShowingLockIcon) { + String contentDescription = mContext.getString( + com.android.internal.R.string.status_bar_device_locked); mStatusBarManager.setIcon("secure", - com.android.internal.R.drawable.stat_sys_secure, 0); + com.android.internal.R.drawable.stat_sys_secure, 0, + contentDescription); mShowingLockIcon = true; } } else { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index b963b131f59f..e0debf7ca994 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -388,6 +388,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { st.isHandled = false; mPreparedPanel = st; + if (st.frozenActionViewState != null) { + st.menu.restoreActionViewStates(st.frozenActionViewState); + st.frozenActionViewState = null; + } + return true; } @@ -652,7 +657,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void invalidatePanelMenu(int featureId) { PanelFeatureState st = getPanelState(featureId, true); + Bundle savedActionViewStates = null; if (st.menu != null) { + savedActionViewStates = new Bundle(); + st.menu.saveActionViewStates(savedActionViewStates); + if (savedActionViewStates.size() > 0) { + st.frozenActionViewState = savedActionViewStates; + } st.menu.clear(); } st.refreshMenuContent = true; @@ -3024,6 +3035,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ Bundle frozenMenuState; + /** + * Contains the state of associated action views when told to freeze. + * These are saved across invalidations. + */ + Bundle frozenActionViewState; + PanelFeatureState(int featureId) { this.featureId = featureId; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index ad6cebb60b78..ae13ab5a17a9 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -166,22 +166,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SYSTEM_DIALOG_LAYER = 6; // toasts and the plugged-in battery thing static final int TOAST_LAYER = 7; - static final int STATUS_BAR_LAYER = 8; - static final int STATUS_BAR_PANEL_LAYER = 9; // SIM errors and unlock. Not sure if this really should be in a high layer. - static final int PRIORITY_PHONE_LAYER = 10; + static final int PRIORITY_PHONE_LAYER = 8; // like the ANR / app crashed dialogs - static final int SYSTEM_ALERT_LAYER = 11; + static final int SYSTEM_ALERT_LAYER = 9; // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 12; + static final int SYSTEM_ERROR_LAYER = 10; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_LAYER = 13; + static final int INPUT_METHOD_LAYER = 11; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_DIALOG_LAYER = 14; + static final int INPUT_METHOD_DIALOG_LAYER = 12; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - static final int KEYGUARD_LAYER = 15; - static final int KEYGUARD_DIALOG_LAYER = 16; + static final int KEYGUARD_LAYER = 13; + static final int KEYGUARD_DIALOG_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 drag layer: input for drag-and-drop is associated with this window, @@ -1703,7 +1703,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr); + if (DEBUG_LAYOUT) { + Log.i(TAG, "mNavigationBar frame: " + navr); + Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", + mDockLeft, mDockTop, mDockRight, mDockBottom)); + } // apply navigation bar insets pf.left = df.left = vf.left = mDockLeft; @@ -1713,6 +1717,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBar.computeFrameLw(pf, df, vf, vf); + // now, let's consider the navigation bar; if it exists, it must be removed from the + // available screen real estate (like an un-hideable status bar) + if (navr != null) { + if (navr.top == 0) { + // Navigation bar is vertical + if (mRestrictedScreenLeft == navr.left) { + mRestrictedScreenLeft = navr.right; + mRestrictedScreenWidth -= (navr.right - navr.left); + } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) { + mRestrictedScreenWidth -= (navr.right - navr.left); + } + } else { + // Navigation bar horizontal, at bottom + if ((mRestrictedScreenHeight+mRestrictedScreenTop) == navr.bottom) { + mRestrictedScreenHeight -= (navr.bottom-navr.top); + } + } + } + if (mStatusBar.isVisibleLw()) { // If the status bar is hidden, we don't want to cause // windows behind it to scroll. @@ -1745,23 +1768,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mRestrictedScreenHeight -= (r.bottom-r.top); } - if (navr != null) { - if (navr.top == 0) { - // Navigation bar is vertical - if (mRestrictedScreenLeft == navr.left) { - mRestrictedScreenLeft = navr.right; - mRestrictedScreenWidth -= (navr.right - navr.left); - } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) { - mRestrictedScreenWidth -= (navr.right - navr.left); - } - } else { - // Navigation bar horizontal, at bottom - if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) { - mRestrictedScreenHeight -= (navr.bottom-navr.top); - } - } - } - mContentTop = mCurTop = mDockTop = mRestrictedScreenTop; mContentBottom = mCurBottom = mDockBottom = mRestrictedScreenTop + mRestrictedScreenHeight; @@ -1873,19 +1879,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { // permission, so they have the same privileges as the status // bar itself. // - // However, they should still dodge the navigation bar if it exists. A - // straightforward way to do this is to only allow the status bar panels to - // extend to the extrema of the allowable region for the IME dock. + // However, they should still dodge the navigation bar if it exists. pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; pf.top = df.top = mUnrestrictedScreenTop; pf.right = df.right = hasNavBar - ? mDockRight + ? mRestrictedScreenLeft+mRestrictedScreenWidth : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; pf.bottom = df.bottom = hasNavBar - ? mDockBottom + ? mRestrictedScreenTop+mRestrictedScreenHeight : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + if (DEBUG_LAYOUT) { + Log.v(TAG, String.format( + "Laying out status bar window: (%d,%d - %d,%d)", + pf.left, pf.top, pf.right, pf.bottom)); + } } else { pf.left = df.left = mRestrictedScreenLeft; pf.top = df.top = mRestrictedScreenTop; @@ -1922,12 +1931,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; pf.top = df.top = cf.top = mUnrestrictedScreenTop; pf.right = df.right = cf.right = hasNavBar - ? mDockRight + ? mRestrictedScreenLeft+mRestrictedScreenWidth : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; pf.bottom = df.bottom = cf.bottom = hasNavBar - ? mDockBottom + ? mRestrictedScreenTop+mRestrictedScreenHeight : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + } else if (attrs.type == TYPE_NAVIGATION_BAR) { + // The navigation bar has Real Ultimate Power. + pf.left = df.left = mUnrestrictedScreenLeft; + pf.top = df.top = mUnrestrictedScreenTop; + pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; + pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + if (DEBUG_LAYOUT) { + Log.v(TAG, String.format( + "Laying out navigation bar window: (%d,%d - %d,%d)", + pf.left, pf.top, pf.right, pf.bottom)); + } } else { pf.left = df.left = cf.left = mRestrictedScreenLeft; pf.top = df.top = cf.top = mRestrictedScreenTop; diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 25979782afde..d39f565f7f84 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -50,6 +50,7 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; @@ -165,7 +166,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final KeyguardManager mKeyguardManager; private final Notification mImeSwitcherNotification; private final PendingIntent mImeSwitchPendingIntent; - private final boolean mShowOngoingImeSwitcherForPhones; + private boolean mShowOngoingImeSwitcherForPhones; private boolean mNotificationShown; class SessionState { @@ -537,8 +538,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeSwitcherNotification.vibrate = null; Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER); mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); - mShowOngoingImeSwitcherForPhones = mRes.getBoolean( - com.android.internal.R.bool.show_ongoing_ime_switcher); + + mShowOngoingImeSwitcherForPhones = false; synchronized (mMethodMap) { mFileManager = new InputMethodFileManager(mMethodMap); @@ -611,6 +612,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { if (!mSystemReady) { mSystemReady = true; + mShowOngoingImeSwitcherForPhones = mRes.getBoolean( + com.android.internal.R.bool.show_ongoing_ime_switcher); try { startInputInnerLocked(); } catch (RuntimeException e) { @@ -1046,7 +1049,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mStatusBar.setIconVisibility("ime", false); } else if (packageName != null) { if (DEBUG) Slog.d(TAG, "show a small icon for the input method"); - mStatusBar.setIcon("ime", packageName, iconId, 0); + CharSequence contentDescription = null; + try { + PackageManager packageManager = mContext.getPackageManager(); + contentDescription = packageManager.getApplicationLabel( + packageManager.getApplicationInfo(packageName, 0)); + } catch (NameNotFoundException nnfe) { + /* ignore */ + } + mStatusBar.setIcon("ime", packageName, iconId, 0, + contentDescription != null ? contentDescription.toString() : null); mStatusBar.setIconVisibility("ime", true); } } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 41e8a3148223..2366fcb41c8d 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -93,6 +93,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { private static final String KEY_TX = "tx_bytes"; class NetdResponseCode { + /* Keep in sync with system/netd/ResponseCode.h */ public static final int InterfaceListResult = 110; public static final int TetherInterfaceListResult = 111; public static final int TetherDnsFwdTgtListResult = 112; @@ -108,6 +109,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { public static final int InterfaceTxThrottleResult = 219; public static final int InterfaceChange = 600; + public static final int BandwidthControl = 601; } /** @@ -265,6 +267,20 @@ class NetworkManagementService extends INetworkManagementService.Stub { } /** + * Notify our observers of a limit reached. + */ + private void notifyLimitReached(String limitName, String iface) { + for (INetworkManagementEventObserver obs : mObservers) { + try { + obs.limitReached(limitName, iface); + Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface); + } catch (Exception ex) { + Slog.w(TAG, "Observer notifier failed", ex); + } + } + } + + /** * Let us know the daemon is connected */ protected void onConnected() { @@ -286,33 +302,52 @@ class NetworkManagementService extends INetworkManagementService.Stub { }.start(); } public boolean onEvent(int code, String raw, String[] cooked) { - if (code == NetdResponseCode.InterfaceChange) { - /* - * a network interface change occured - * Format: "NNN Iface added <name>" - * "NNN Iface removed <name>" - * "NNN Iface changed <name> <up/down>" - * "NNN Iface linkstatus <name> <up/down>" - */ - if (cooked.length < 4 || !cooked[1].equals("Iface")) { + switch (code) { + case NetdResponseCode.InterfaceChange: + /* + * a network interface change occured + * Format: "NNN Iface added <name>" + * "NNN Iface removed <name>" + * "NNN Iface changed <name> <up/down>" + * "NNN Iface linkstatus <name> <up/down>" + */ + if (cooked.length < 4 || !cooked[1].equals("Iface")) { + throw new IllegalStateException( + String.format("Invalid event from daemon (%s)", raw)); + } + if (cooked[2].equals("added")) { + notifyInterfaceAdded(cooked[3]); + return true; + } else if (cooked[2].equals("removed")) { + notifyInterfaceRemoved(cooked[3]); + return true; + } else if (cooked[2].equals("changed") && cooked.length == 5) { + notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); + return true; + } else if (cooked[2].equals("linkstate") && cooked.length == 5) { + notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); + return true; + } throw new IllegalStateException( String.format("Invalid event from daemon (%s)", raw)); - } - if (cooked[2].equals("added")) { - notifyInterfaceAdded(cooked[3]); - return true; - } else if (cooked[2].equals("removed")) { - notifyInterfaceRemoved(cooked[3]); - return true; - } else if (cooked[2].equals("changed") && cooked.length == 5) { - notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); - return true; - } else if (cooked[2].equals("linkstate") && cooked.length == 5) { - notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); - return true; - } - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + // break; + case NetdResponseCode.BandwidthControl: + /* + * Bandwidth control needs some attention + * Format: "NNN limit alert <alertName> <ifaceName>" + */ + if (cooked.length < 5 || !cooked[1].equals("limit")) { + throw new IllegalStateException( + String.format("Invalid event from daemon (%s)", raw)); + } + if (cooked[2].equals("alert")) { + notifyLimitReached(cooked[3], cooked[4]); + return true; + } + throw new IllegalStateException( + String.format("Invalid event from daemon (%s)", raw)); + // break; + default: break; } return false; } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 4ecdfed687c3..5d7a48f491f4 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -262,7 +262,7 @@ public class NotificationManagerService extends INotificationManager.Stub public void onNotificationClick(String pkg, String tag, int id) { cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL, - Notification.FLAG_FOREGROUND_SERVICE, true); + Notification.FLAG_FOREGROUND_SERVICE, false); } public void onNotificationClear(String pkg, String tag, int id) { diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index 286a9376981d..4ced83c9c672 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -22,10 +22,10 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.os.IBinder; -import android.os.RemoteException; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; import android.util.Slog; import android.view.View; @@ -175,7 +175,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } - public void setIcon(String slot, String iconPackage, int iconId, int iconLevel) { + public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, + String contentDescription) { enforceStatusBar(); synchronized (mIcons) { @@ -184,7 +185,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub throw new SecurityException("invalid status bar icon slot: " + slot); } - StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel); + StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel, 0, + contentDescription); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); mIcons.setIcon(index, icon); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 8c7e279b7132..766659153821 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -230,6 +230,7 @@ class ServerThread extends Thread { WallpaperManagerService wallpaper = null; LocationManagerService location = null; CountryDetectorService countryDetector = null; + TextServicesManagerService tsms = null; if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { @@ -273,6 +274,14 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "Text Service Manager Service"); + tsms = new TextServicesManagerService(context); + ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting Text Service Manager Service", e); + } + + try { Slog.i(TAG, "NetworkStats Service"); networkStats = new NetworkStatsService(context, networkManagement, alarm); ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); @@ -538,6 +547,7 @@ class ServerThread extends Thread { final LocationManagerService locationF = location; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; + final TextServicesManagerService textServiceManagerServiceF = tsms; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -571,6 +581,7 @@ class ServerThread extends Thread { if (countryDetectorF != null) countryDetectorF.systemReady(); if (throttleF != null) throttleF.systemReady(); if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady(); + if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); } }); diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java new file mode 100644 index 000000000000..4a0c837df0c6 --- /dev/null +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -0,0 +1,346 @@ +/* + * 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.server; + +import com.android.internal.content.PackageMonitor; +import com.android.internal.textservice.ISpellCheckerService; +import com.android.internal.textservice.ISpellCheckerSession; +import com.android.internal.textservice.ISpellCheckerSessionListener; +import com.android.internal.textservice.ITextServicesManager; +import com.android.internal.textservice.ITextServicesSessionListener; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.provider.Settings; +import android.text.TextUtils; +import android.service.textservice.SpellCheckerService; +import android.util.Log; +import android.util.Slog; +import android.view.textservice.SpellCheckerInfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class TextServicesManagerService extends ITextServicesManager.Stub { + private static final String TAG = TextServicesManagerService.class.getSimpleName(); + private static final boolean DBG = false; + + private final Context mContext; + private boolean mSystemReady; + private final TextServicesMonitor mMonitor; + private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = + new HashMap<String, SpellCheckerInfo>(); + private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>(); + private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = + new HashMap<String, SpellCheckerBindGroup>(); + + public void systemReady() { + if (!mSystemReady) { + mSystemReady = true; + } + } + + public TextServicesManagerService(Context context) { + mSystemReady = false; + mContext = context; + mMonitor = new TextServicesMonitor(); + mMonitor.register(context, true); + synchronized (mSpellCheckerMap) { + buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap); + } + } + + private class TextServicesMonitor extends PackageMonitor { + @Override + public void onSomePackagesChanged() { + synchronized (mSpellCheckerMap) { + buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap); + // TODO: Update for each locale + SpellCheckerInfo sci = getCurrentSpellChecker(null); + if (sci == null) { + sci = findAvailSpellCheckerLocked(null, null); + if (sci == null) return; + // Set the current spell checker if there is one or more spell checkers + // available. In this case, "sci" is the first one in the available spell + // checkers. + setCurrentSpellChecker(sci); + } + final String packageName = sci.getPackageName(); + final int change = isPackageDisappearing(packageName); + if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) { + // Package disappearing + setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName)); + } else if (isPackageModified(packageName)) { + // Package modified + setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName)); + } + } + } + } + + private static void buildSpellCheckerMapLocked(Context context, + ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) { + list.clear(); + map.clear(); + final PackageManager pm = context.getPackageManager(); + List<ResolveInfo> services = pm.queryIntentServices( + new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA); + final int N = services.size(); + for (int i = 0; i < N; ++i) { + final ResolveInfo ri = services.get(i); + final ServiceInfo si = ri.serviceInfo; + final ComponentName compName = new ComponentName(si.packageName, si.name); + if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) { + Slog.w(TAG, "Skipping text service " + compName + + ": it does not require the permission " + + android.Manifest.permission.BIND_TEXT_SERVICE); + continue; + } + if (DBG) Slog.d(TAG, "Add: " + compName); + final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri); + list.add(sci); + map.put(sci.getId(), sci); + } + } + + // TODO: find an appropriate spell checker for specified locale + private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) { + final int spellCheckersCount = mSpellCheckerList.size(); + if (spellCheckersCount == 0) { + Slog.w(TAG, "no available spell checker services found"); + return null; + } + if (prefPackage != null) { + for (int i = 0; i < spellCheckersCount; ++i) { + final SpellCheckerInfo sci = mSpellCheckerList.get(i); + if (prefPackage.equals(sci.getPackageName())) { + return sci; + } + } + } + if (spellCheckersCount > 1) { + Slog.w(TAG, "more than one spell checker service found, picking first"); + } + return mSpellCheckerList.get(0); + } + + // TODO: Save SpellCheckerService by supported languages. Currently only one spell + // checker is saved. + @Override + public SpellCheckerInfo getCurrentSpellChecker(String locale) { + synchronized (mSpellCheckerMap) { + final String curSpellCheckerId = + Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_SERVICE); + if (TextUtils.isEmpty(curSpellCheckerId)) { + return null; + } + return mSpellCheckerMap.get(curSpellCheckerId); + } + } + + @Override + public void getSpellCheckerService(SpellCheckerInfo info, String locale, + ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) { + if (!mSystemReady) { + return; + } + if (info == null || tsListener == null) { + Slog.e(TAG, "getSpellCheckerService: Invalid input."); + return; + } + final String sciId = info.getId(); + synchronized(mSpellCheckerMap) { + if (!mSpellCheckerMap.containsKey(sciId)) { + return; + } + if (mSpellCheckerBindGroups.containsKey(sciId)) { + mSpellCheckerBindGroups.get(sciId).addListener(tsListener, locale, scListener); + return; + } + final InternalServiceConnection connection = new InternalServiceConnection( + sciId, locale, scListener); + final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); + serviceIntent.setComponent(info.getComponent()); + if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { + Slog.e(TAG, "Failed to get a spell checker service."); + return; + } + final SpellCheckerBindGroup group = new SpellCheckerBindGroup( + connection, tsListener, locale, scListener); + mSpellCheckerBindGroups.put(sciId, group); + } + return; + } + + @Override + public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { + synchronized(mSpellCheckerMap) { + for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { + if (group == null) continue; + group.removeListener(listener); + } + } + } + + private void setCurrentSpellChecker(SpellCheckerInfo sci) { + if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return; + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId()); + } + + // SpellCheckerBindGroup contains active text service session listeners. + // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from + // mSpellCheckerBindGroups + private class SpellCheckerBindGroup { + final InternalServiceConnection mInternalConnection; + final ArrayList<InternalDeathRecipient> mListeners = + new ArrayList<InternalDeathRecipient>(); + + public SpellCheckerBindGroup(InternalServiceConnection connection, + ITextServicesSessionListener listener, String locale, + ISpellCheckerSessionListener scListener) { + mInternalConnection = connection; + addListener(listener, locale, scListener); + } + + public void onServiceConnected(ISpellCheckerService spellChecker) { + synchronized(mSpellCheckerMap) { + for (InternalDeathRecipient listener : mListeners) { + try { + final ISpellCheckerSession session = spellChecker.getISpellCheckerSession( + listener.mScLocale, listener.mScListener); + listener.mTsListener.onServiceConnected(session); + } catch (RemoteException e) { + } + } + } + } + + public void addListener(ITextServicesSessionListener tsListener, String locale, + ISpellCheckerSessionListener scListener) { + synchronized(mSpellCheckerMap) { + try { + final int size = mListeners.size(); + for (int i = 0; i < size; ++i) { + if (mListeners.get(i).hasSpellCheckerListener(scListener)) { + // do not add the lister if the group already contains this. + return; + } + } + final InternalDeathRecipient recipient = new InternalDeathRecipient( + this, tsListener, locale, scListener); + scListener.asBinder().linkToDeath(recipient, 0); + mListeners.add(new InternalDeathRecipient( + this, tsListener, locale, scListener)); + } catch(RemoteException e) { + // do nothing + } + cleanLocked(); + } + } + + public void removeListener(ISpellCheckerSessionListener listener) { + synchronized(mSpellCheckerMap) { + final int size = mListeners.size(); + final ArrayList<InternalDeathRecipient> removeList = + new ArrayList<InternalDeathRecipient>(); + for (int i = 0; i < size; ++i) { + final InternalDeathRecipient tempRecipient = mListeners.get(i); + if(tempRecipient.hasSpellCheckerListener(listener)) { + removeList.add(tempRecipient); + } + } + final int removeSize = removeList.size(); + for (int i = 0; i < removeSize; ++i) { + mListeners.remove(removeList.get(i)); + } + cleanLocked(); + } + } + + private void cleanLocked() { + if (mListeners.isEmpty()) { + mSpellCheckerBindGroups.remove(this); + // Unbind service when there is no active clients. + mContext.unbindService(mInternalConnection); + } + } + } + + private class InternalServiceConnection implements ServiceConnection { + private final ISpellCheckerSessionListener mListener; + private final String mSciId; + private final String mLocale; + public InternalServiceConnection( + String id, String locale, ISpellCheckerSessionListener listener) { + mSciId = id; + mLocale = locale; + mListener = listener; + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized(mSpellCheckerMap) { + ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service); + final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); + if (group != null) { + group.onServiceConnected(spellChecker); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mSpellCheckerBindGroups.remove(mSciId); + } + } + + private class InternalDeathRecipient implements IBinder.DeathRecipient { + public final ITextServicesSessionListener mTsListener; + public final ISpellCheckerSessionListener mScListener; + public final String mScLocale; + private final SpellCheckerBindGroup mGroup; + public InternalDeathRecipient(SpellCheckerBindGroup group, + ITextServicesSessionListener tsListener, String scLocale, + ISpellCheckerSessionListener scListener) { + mTsListener = tsListener; + mScListener = scListener; + mScLocale = scLocale; + mGroup = group; + } + + public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { + return mScListener.equals(listener); + } + + @Override + public void binderDied() { + mGroup.removeListener(mScListener); + } + } +} diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java index b8890aa2aa8e..cd649ce4c554 100644 --- a/services/java/com/android/server/ThrottleService.java +++ b/services/java/com/android/server/ThrottleService.java @@ -194,6 +194,7 @@ public class ThrottleService extends IThrottleManager.Stub { } public void interfaceRemoved(String iface) {} + public void limitReached(String limitName, String iface) {} } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 711255327499..f9f63b1d1bd6 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -1461,7 +1461,7 @@ public class WifiService extends IWifiManager.Stub { if (mMulticasters.size() != 0) { return; } else { - mWifiStateMachine.startPacketFiltering(); + mWifiStateMachine.startFilteringMulticastV4Packets(); } } } @@ -1472,11 +1472,11 @@ public class WifiService extends IWifiManager.Stub { synchronized (mMulticasters) { mMulticastEnabled++; mMulticasters.add(new Multicaster(tag, binder)); - // Note that we could call stopPacketFiltering only when + // Note that we could call stopFilteringMulticastV4Packets only when // our new size == 1 (first call), but this function won't // be called often and by making the stopPacket call each // time we're less fragile and self-healing. - mWifiStateMachine.stopPacketFiltering(); + mWifiStateMachine.stopFilteringMulticastV4Packets(); } int uid = Binder.getCallingUid(); @@ -1513,7 +1513,7 @@ public class WifiService extends IWifiManager.Stub { removed.unlinkDeathRecipient(); } if (mMulticasters.size() == 0) { - mWifiStateMachine.startPacketFiltering(); + mWifiStateMachine.startFilteringMulticastV4Packets(); } Long ident = Binder.clearCallingIdentity(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 0924b862c251..3389f339a7f2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3628,6 +3628,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.forcingToForeground = null; app.foregroundServices = false; + app.hasShownUi = false; app.debugging = false; mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); @@ -9218,6 +9219,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.forcingToForeground = null; app.foregroundServices = false; app.foregroundActivities = false; + app.hasShownUi = false; killServicesLocked(app, true); @@ -9331,8 +9333,6 @@ public final class ActivityManagerService extends ActivityManagerNative // This app is persistent, so we need to keep its record around. // If it is not already on the pending app list, add it there // and start a new process for it. - app.forcingToForeground = null; - app.foregroundServices = false; if (mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); restart = true; @@ -12728,21 +12728,31 @@ public final class ActivityManagerService extends ActivityManagerNative while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) { ServiceRecord s = jt.next(); if (s.startRequested) { - if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { - // This service has seen some activity within - // recent memory, so we will keep its process ahead - // of the background processes. + if (app.hasShownUi) { + // If this process has shown some UI, let it immediately + // go to the LRU list because it may be pretty heavy with + // UI stuff. We'll tag it with a label just to help + // debug and understand what is going on. if (adj > SECONDARY_SERVER_ADJ) { - adj = SECONDARY_SERVER_ADJ; - app.adjType = "started-services"; - app.hidden = false; + app.adjType = "started-bg-ui-services"; + } + } else { + if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { + // This service has seen some activity within + // recent memory, so we will keep its process ahead + // of the background processes. + if (adj > SECONDARY_SERVER_ADJ) { + adj = SECONDARY_SERVER_ADJ; + app.adjType = "started-services"; + app.hidden = false; + } + } + // If we have let the service slide into the background + // state, still have some text describing what it is doing + // even though the service no longer has an impact. + if (adj > SECONDARY_SERVER_ADJ) { + app.adjType = "started-bg-services"; } - } - // If we have let the service slide into the background - // state, still have some text describing what it is doing - // even though the service no longer has an impact. - if (adj > SECONDARY_SERVER_ADJ) { - app.adjType = "started-bg-services"; } // Don't kill this process because it is doing work; it // has said it is doing work. @@ -13351,15 +13361,15 @@ public final class ActivityManagerService extends ActivityManagerNative break; } } - } else if (app.curAdj >= PERCEPTIBLE_APP_ADJ) { - if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_INVISIBLE + } else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) { + if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_BACKGROUND && app.thread != null) { try { - app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_INVISIBLE); + app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_BACKGROUND); } catch (RemoteException e) { } } - app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_INVISIBLE; + app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND; } else { app.trimMemoryLevel = 0; } @@ -13442,7 +13452,7 @@ public final class ActivityManagerService extends ActivityManagerNative } public boolean profileControl(String process, boolean start, - String path, ParcelFileDescriptor fd) throws RemoteException { + String path, ParcelFileDescriptor fd, int profileType) throws RemoteException { try { synchronized (this) { @@ -13487,7 +13497,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - proc.thread.profilerControl(start, path, fd); + proc.thread.profilerControl(start, path, fd, profileType); fd = null; return true; } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 0d89081b0813..cc58eafe8872 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -559,6 +559,7 @@ final class ActivityStack { r.forceNewConfig = false; showAskCompatModeDialogLocked(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); + app.hasShownUi = true; app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r), r.info, r.compat, r.icicle, results, newIntents, !andResume, diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 9e597aa93d18..5b593638f31a 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -66,6 +66,7 @@ class ProcessRecord { boolean setIsForeground; // Running foreground UI when last set? boolean foregroundServices; // Running any services that are foreground? boolean foregroundActivities; // Running any activities that are foreground? + boolean hasShownUi; // Has UI been shown in this process since it was started? boolean bad; // True if disabled in the bad process list boolean killedBackground; // True when proc has been killed due to too many bg String waitingToKill; // Process is waiting to be killed when in the bg; reason @@ -185,6 +186,7 @@ class ProcessRecord { pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup); pw.print(" setSchedGroup="); pw.print(setSchedGroup); pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel); + pw.print(" hasShownUi="); pw.println(hasShownUi); pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground); pw.print(" foregroundServices="); pw.print(foregroundServices); pw.print(" forcingToForeground="); pw.println(forcingToForeground); diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index d7d4b0346795..82bc505ea707 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -288,6 +288,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } + public void limitReached(String limitName, String iface) {} + public int tether(String iface) { Log.d(TAG, "Tethering " + iface); TetherInterfaceSM sm = null; diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index 05e95a7d3d89..cf75d6bbaed0 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -248,6 +248,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } } + public void limitReached(String limitName, String iface) {} + private void showNotification(VpnConfig config, String label, Bitmap icon) { NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index c80cd0a87115..f183f83cfba0 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -19,6 +19,7 @@ package com.android.server.usb; import android.app.PendingIntent; import android.app.Notification; import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -80,6 +81,7 @@ public class UsbDeviceManager { private static final int MSG_ENABLE_ADB = 1; private static final int MSG_SET_CURRENT_FUNCTION = 2; private static final int MSG_SYSTEM_READY = 3; + private static final int MSG_BOOT_COMPLETED = 4; // Delay for debouncing USB disconnects. // We often get rapid connect/disconnect events when enabling USB functions, @@ -87,7 +89,7 @@ public class UsbDeviceManager { private static final int UPDATE_DELAY = 1000; private UsbHandler mHandler; - private boolean mSystemReady; + private boolean mBootCompleted; private final Context mContext; private final ContentResolver mContentResolver; @@ -141,10 +143,15 @@ public class UsbDeviceManager { Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mHandler = new UsbHandler(thread.getLooper()); + + if (nativeIsStartRequested()) { + if (DEBUG) Slog.d(TAG, "accessory attached at boot"); + setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false); + } } public void systemReady() { - mSystemReady = true; + if (DEBUG) Slog.d(TAG, "systemReady"); mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -236,15 +243,22 @@ public class UsbDeviceManager { private String mCurrentFunctions; private String mDefaultFunctions; private UsbAccessory mCurrentAccessory; - private boolean mDeferAccessoryAttached; private int mUsbNotificationId; private boolean mAdbNotificationShown; + private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (DEBUG) Slog.d(TAG, "boot completed"); + mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); + } + }; + private static final int NOTIFICATION_NONE = 0; private static final int NOTIFICATION_MTP = 1; private static final int NOTIFICATION_PTP = 2; private static final int NOTIFICATION_INSTALLER = 3; - private static final int NOTIFICATION_ADB = 4; + private static final int NOTIFICATION_ACCESSORY = 4; + private static final int NOTIFICATION_ADB = 5; public UsbHandler(Looper looper) { super(looper); @@ -285,6 +299,9 @@ public class UsbDeviceManager { // Watch for USB configuration changes mUEventObserver.startObserving(USB_STATE_MATCH); mUEventObserver.startObserving(ACCESSORY_START_MATCH); + + mContext.registerReceiver(mBootCompletedReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } catch (Exception e) { Slog.e(TAG, "Error initializing UsbHandler", e); } @@ -406,11 +423,9 @@ public class UsbDeviceManager { mCurrentAccessory = new UsbAccessory(strings); Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); // defer accessoryAttached if system is not ready - if (mSystemReady) { + if (mBootCompleted) { mSettingsManager.accessoryAttached(mCurrentAccessory); - } else { - mDeferAccessoryAttached = true; - } + } // else handle in mBootCompletedReceiver } else { Slog.e(TAG, "nativeGetAccessoryStrings failed"); } @@ -421,7 +436,7 @@ public class UsbDeviceManager { setEnabledFunctions(mDefaultFunctions); if (mCurrentAccessory != null) { - if (mSystemReady) { + if (mBootCompleted) { mSettingsManager.accessoryDetached(mCurrentAccessory); } mCurrentAccessory = null; @@ -463,7 +478,7 @@ public class UsbDeviceManager { // restore defaults when USB is disconnected doSetCurrentFunctions(mDefaultFunctions); } - if (mSystemReady) { + if (mBootCompleted) { updateUsbState(); } break; @@ -497,7 +512,10 @@ public class UsbDeviceManager { updateUsbNotification(); updateAdbNotification(); updateUsbState(); - if (mCurrentAccessory != null && mDeferAccessoryAttached) { + break; + case MSG_BOOT_COMPLETED: + mBootCompleted = true; + if (mCurrentAccessory != null) { mSettingsManager.accessoryAttached(mCurrentAccessory); } break; @@ -527,6 +545,10 @@ public class UsbDeviceManager { title = r.getText( com.android.internal.R.string.usb_cd_installer_notification_title); id = NOTIFICATION_INSTALLER; + } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { + title = r.getText( + com.android.internal.R.string.usb_accessory_notification_title); + id = NOTIFICATION_ACCESSORY; } else { Slog.e(TAG, "No known USB function in updateUsbNotification"); } @@ -671,4 +693,5 @@ public class UsbDeviceManager { private native String[] nativeGetAccessoryStrings(); private native ParcelFileDescriptor nativeOpenAccessory(); + private native boolean nativeIsStartRequested(); } diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/jni/com_android_server_UsbDeviceManager.cpp index 69541714260e..40f0dbd81430 100644 --- a/services/jni/com_android_server_UsbDeviceManager.cpp +++ b/services/jni/com_android_server_UsbDeviceManager.cpp @@ -99,11 +99,26 @@ static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobjec gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); } +static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv *env, jobject thiz) +{ + int fd = open(DRIVER_NAME, O_RDWR); + if (fd < 0) { + LOGE("could not open %s", DRIVER_NAME); + return false; + } + int result = ioctl(fd, ACCESSORY_IS_START_REQUESTED); + close(fd); + return (result == 1); +} + + static JNINativeMethod method_table[] = { { "nativeGetAccessoryStrings", "()[Ljava/lang/String;", (void*)android_server_UsbDeviceManager_getAccessoryStrings }, { "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;", (void*)android_server_UsbDeviceManager_openAccessory }, + { "nativeIsStartRequested", "()Z", + (void*)android_server_UsbDeviceManager_isStartRequested }, }; int register_android_server_UsbDeviceManager(JNIEnv *env) diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index 11f61ccb1ada..40659d4d16be 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -60,6 +60,10 @@ status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp, sp<Layer> layer(mLayer.promote()); if (layer != NULL) { + uint32_t orientation = layer->getOrientation(); + if (orientation & Transform::ROT_INVALID) { + orientation = 0; + } *outTransform = layer->getOrientation(); } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 40a70a806ce1..a0961caaa40d 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -806,10 +806,10 @@ public abstract class PhoneBase extends Handler implements Phone { mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType)); } - public void notifyDataConnection() { + public void notifyDataConnection(String reason) { String types[] = getActiveApnTypes(); for (String apnType : types) { - mNotifier.notifyDataConnection(this, null, apnType, getDataConnectionState(apnType)); + mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType)); } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java index 0d551aade502..5df2edd6a281 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java @@ -134,8 +134,6 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } } - // Not sure if this is needed in CDMALTE phone. - // mDataRoaming = regCodeIsRoaming(regState); mLteSS.setRadioTechnology(type); mLteSS.setState(regCodeToServiceState(regState)); } else { @@ -345,13 +343,14 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } if (cm.getSimState().isSIMReady()) { - // SIM is found on the device. If ERI roaming is OFF, use operator name - // from CSIM record. + // SIM is found on the device. If ERI roaming is OFF and SID/NID matches + // one configfured in SIM, use operator name from CSIM record. boolean showSpn = ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition(); int iconIndex = ss.getCdmaEriIconIndex(); - if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF)) { + if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && + isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) { ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName()); } } @@ -401,7 +400,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) { - phone.notifyDataConnection(); + phone.notifyDataConnection(null); } if (hasRoamingOn) { @@ -469,6 +468,34 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } /** + * Check whether the specified SID and NID pair appears in the HOME SID/NID list + * read from NV or SIM. + * + * @return true if provided sid/nid pair belongs to operator's home network. + */ + private boolean isInHomeSidNid(int sid, int nid) { + // if SID/NID is not available, assume this is home network. + if (isSidsAllZeros()) return true; + + // length of SID/NID shold be same + if (mHomeSystemId.length != mHomeNetworkId.length) return true; + + if (sid == 0) return true; + + for (int i = 0; i < mHomeSystemId.length; i++) { + // Use SID only if NID is a reserved value. + // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) + if ((mHomeSystemId[i] == sid) && + ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || + (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { + return true; + } + } + // SID/NID are not in the list. So device is not in home network + return false; + } + + /** * Returns OTASP_NOT_NEEDED as its not needed for LTE */ @Override diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 24a468a7d2c1..2cf4b8812a37 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -130,8 +130,8 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { protected String mCurPlmn = null; protected String mMdn; - private int mHomeSystemId[] = null; - private int mHomeNetworkId[] = null; + protected int mHomeSystemId[] = null; + protected int mHomeNetworkId[] = null; protected String mMin; protected String mPrlVersion; protected boolean mIsMinInfoReady = false; @@ -999,7 +999,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { } if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) { - phone.notifyDataConnection(); + phone.notifyDataConnection(null); } if (hasRoamingOn) { @@ -1481,7 +1481,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { } } - private boolean isSidsAllZeros() { + protected boolean isSidsAllZeros() { if (mHomeSystemId != null) { for (int i=0; i < mHomeSystemId.length; i++) { if (mHomeSystemId[i] != 0) { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 93f4b4ea579a..d3645faba86f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -915,7 +915,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } if (hasRadioTechnologyChanged) { - phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED, Phone.APN_TYPE_ALL); + phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED); } if (hasRoamingOn) { diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java index 1493ab9ffcd8..13b6129ab1ac 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java @@ -93,12 +93,9 @@ public class ListActivity extends Activity { } public void startProfiling(View v) { - ViewDebug.startLooperProfiling(new File(Environment.getExternalStorageDirectory(), - "looper.trace")); } public void stopProfiling(View v) { - ViewDebug.stopLooperProfiling(); } @Override diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java index b21253342093..e75a0797dfa7 100644 --- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java @@ -100,22 +100,22 @@ public class StatusBarTest extends TestActivity new Test("Double Remove") { public void run() { Log.d(TAG, "set 0"); - mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0, null); Log.d(TAG, "remove 1"); mStatusBarManager.removeIcon("tty"); SystemClock.sleep(1000); Log.d(TAG, "set 1"); - mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0, null); if (false) { Log.d(TAG, "set 2"); - mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0, null); } Log.d(TAG, "remove 2"); mStatusBarManager.removeIcon("tty"); Log.d(TAG, "set 3"); - mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0, null); } }, new Test("Hide (FLAG_FULLSCREEN)") { diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml index 663cc0dbea6f..ab61a9e25bb7 100644 --- a/tests/TileBenchmark/AndroidManifest.xml +++ b/tests/TileBenchmark/AndroidManifest.xml @@ -7,14 +7,16 @@ android:label="@string/app_name" android:hardwareAccelerated="true"> <activity android:name=".ProfileActivity" - android:label="@string/profile_activity"> + android:label="@string/profile_activity" + android:theme="@android:style/Theme.Holo.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".PlaybackActivity" - android:label="@string/playback_activity"> + android:label="@string/playback_activity" + android:theme="@android:style/Theme.Holo.NoActionBar"> </activity> </application> </manifest> diff --git a/tests/TileBenchmark/res/layout/main.xml b/tests/TileBenchmark/res/layout/main.xml index 4a81da65edb9..577c466e3847 100644 --- a/tests/TileBenchmark/res/layout/main.xml +++ b/tests/TileBenchmark/res/layout/main.xml @@ -23,11 +23,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" > - <Button - android:id="@+id/inspect" + <Spinner + android:id="@+id/movement" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/inspect_log" + android:prompt="@string/movement_method" /> <Spinner android:id="@+id/velocity" @@ -36,6 +36,13 @@ android:gravity="center_horizontal" android:prompt="@string/desired_scroll_velocity" /> + <ToggleButton + android:id="@+id/capture" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textOn="@string/capture_stop" + android:textOff="@string/capture_start" + /> <EditText android:id="@+id/url" android:layout_width="0dip" @@ -44,6 +51,12 @@ android:imeOptions="actionGo" android:layout_weight="1" /> + <Button + android:id="@+id/inspect" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/inspect_log" + /> </LinearLayout> <com.test.tilebenchmark.ProfiledWebView android:id="@+id/web" diff --git a/tests/TileBenchmark/res/values/colors.xml b/tests/TileBenchmark/res/values/colors.xml index 3958083febd5..dbb8e7295b8b 100644 --- a/tests/TileBenchmark/res/values/colors.xml +++ b/tests/TileBenchmark/res/values/colors.xml @@ -18,8 +18,17 @@ <color name="ready_tile">#ff4ac230</color> <!-- The color of tiles with stale / invalid textures --> <color name="unready_tile">#ff744400</color> - <!-- Background color for logged URLs --> - <color name="finished_url">#ff004000</color> - <!-- Background color for URLs with logging in progress --> - <color name="unfinished_url">#ff400000</color> + <!-- Viewport overlay in playback --> + <color name="view">#50000050</color> + <!-- Invalidated region overlay in playback - start color --> + <color name="inval_region_start">#80ff0000</color> + <!-- Invalidated region overlay in playback - stop color--> + <color name="inval_region_stop">#80ffffff</color> + + <!-- Background color for not testing --> + <color name="background_not_testing">#ff000000</color> + <!-- Background color for during testing --> + <color name="background_start_testing">#ff400000</color> + <!-- Background color for testing complete --> + <color name="background_stop_testing">#ff004000</color> </resources> diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml index f70ee2c04a3f..66972ac26bab 100644 --- a/tests/TileBenchmark/res/values/strings.xml +++ b/tests/TileBenchmark/res/values/strings.xml @@ -28,6 +28,10 @@ <string name="loadbutton">Load</string> <!-- Button, opens the playback activity [CHAR LIMIT=20] --> <string name="inspect_log">Inspect Log</string> + <!-- ToggleButton label when pressing starts capture [CHAR LIMIT=15] --> + <string name="capture_start">Start Capture</string> + <!-- ToggleButton label when pressing stops capture [CHAR LIMIT=15] --> + <string name="capture_stop">Stop Capture</string> <!-- The speed of auto-scrolling [CHAR LIMIT=30] --> <string name="desired_scroll_velocity">Choose Scroll Velocity</string> <!-- Pixels moved per frame [CHAR LIMIT=10] --> @@ -39,6 +43,21 @@ <item>200</item> <item>400</item> </string-array> + <!-- Drop down menu for selecting scrolling vs manual navigation for + capturing [CHAR LIMIT=15] --> + <string name="movement_method">Movement Method</string> + <!-- Drop down menu entry - automatically scroll to the end of the page + with scrollBy() [CHAR LIMIT=15] --> + <string name="movement_auto_scroll">Auto-scroll</string> + <!-- Drop down menu entry - [CHAR LIMIT=15] --> + <string name="movement_auto_fling">Auto-fling</string> + <!-- Drop down menu entry - manually navigate the page(s), hit 'capture' + button [CHAR LIMIT=15] --> + <string name="movement_manual">Manual</string> + + <!-- Error popup indicating log data couldn't be loaded [CHAR LIMIT=60] --> + <string name="error_no_data">Error: log data could not be loaded.</string> + <!-- 25th percentile - 25% of frames fall below this value [CHAR LIMIT=12] --> <string name="percentile_25">25%ile</string> @@ -56,7 +75,7 @@ <string name="format_stat">%4.4f</string> <!-- Format string for displaying aggregate stats+values (nr of valid tiles, etc.) [CHAR LIMIT=20] --> - <string name="format_stat_name">%1$9s %2$3d</string> + <string name="format_stat_name">%1$-20s %2$3d</string> <!-- Text hovering over canvas, number of tiles ready [CHAR LIMIT=15] --> <string name="ready_tiles">Ready Tiles</string> <!-- Text hovering over canvas, number tiles not ready [CHAR LIMIT=15] --> @@ -64,4 +83,7 @@ <!-- Text hovering over canvas, number of tiles that haven't been allocated to a place on the page [CHAR LIMIT=15] --> <string name="unplaced_tiles">Unplaced Tiles</string> + <!-- Text hovering over canvas, number of invalidated regions this frame + [CHAR LIMIT=15] --> + <string name="number_invalidates">Invalidates</string> </resources> diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java index 5130f5d3ab3f..36694a7476f4 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java @@ -27,6 +27,7 @@ import android.widget.Button; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; +import android.widget.Toast; import java.io.FileInputStream; import java.io.IOException; @@ -102,7 +103,10 @@ public class PlaybackActivity extends Activity { @Override protected void onPostExecute(TileData data[][]) { if (data == null) { - data = genTestPattern(); + Toast.makeText(getApplicationContext(), + getResources().getString(R.string.error_no_data), + Toast.LENGTH_LONG).show(); + return; } mPlaybackView.setData(data); @@ -166,23 +170,4 @@ public class PlaybackActivity extends Activity { new LoadFileTask().execute(ProfileActivity.TEMP_FILENAME); } - - private TileData[][] genTestPattern() { - final int XMAX = 5; - final int FRAMEMAX = 99; - - TileData example[][] = new TileData[FRAMEMAX][]; - for (int frame = 0; frame < FRAMEMAX; frame++) { - int numTiles = frame + 10; - - example[frame] = new TileData[numTiles]; - for (int t = 0; t < numTiles; t++) { - int x = t % XMAX; - int y = t / XMAX; - boolean isReady = y * 10 < frame; - example[frame][t] = new TileData(x, y, isReady, 0); - } - } - return example; - } } diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java index db4a34182bac..35b1563ed895 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java @@ -28,19 +28,17 @@ import java.util.ArrayList; import java.util.Arrays; public class PlaybackGraphs { - private static final int BAR_WIDTH = PlaybackView.TILEX * 3; + private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3; private static final float CANVAS_SCALE = 0.2f; private static final double IDEAL_FRAMES = 60; private static final int LABELOFFSET = 100; private static Paint whiteLabels; - private static double viewportCoverage(int l, int b, int r, int t, - int tileIndexX, - int tileIndexY) { - if (tileIndexX * PlaybackView.TILEX < r - && (tileIndexX + 1) * PlaybackView.TILEX >= l - && tileIndexY * PlaybackView.TILEY < t - && (tileIndexY + 1) * PlaybackView.TILEY >= b) { + private static double viewportCoverage(TileData view, TileData tile) { + if (tile.left < view.right + && tile.right >= view.left + && tile.top < view.bottom + && tile.bottom >= view.top) { return 1.0f; } return 0.0f; @@ -76,13 +74,10 @@ public class PlaybackGraphs { // coverage graph @Override public double getValue(TileData[] frame) { - int l = frame[0].x, b = frame[0].y; - int r = frame[1].x, t = frame[1].y; double total = 0, totalCount = 0; - for (int tileID = 2; tileID < frame.length; tileID++) { + for (int tileID = 1; tileID < frame.length; tileID++) { TileData data = frame[tileID]; - double coverage = viewportCoverage(l, b, r, t, data.x, - data.y); + double coverage = viewportCoverage(frame[0], data); total += coverage * (data.isReady ? 1 : 0); totalCount += coverage; } @@ -158,7 +153,7 @@ public class PlaybackGraphs { public PlaybackGraphs() { whiteLabels = new Paint(); whiteLabels.setColor(Color.WHITE); - whiteLabels.setTextSize(PlaybackView.TILEY / 3); + whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3); } private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>(); @@ -177,11 +172,13 @@ public class PlaybackGraphs { int lastBar = 0; for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) { TileData frame[] = tileProfilingData[frameIndex]; - int newBar = (frame[0].y + frame[1].y) / 2; + int newBar = (frame[0].top + frame[0].bottom) / 2; MetricGen s = Metrics[metricIndex]; double absoluteValue = s.getValue(frame); double relativeValue = absoluteValue / s.getMax(); + relativeValue = Math.min(1,relativeValue); + relativeValue = Math.max(0,relativeValue); int rightPos = (int) (-BAR_WIDTH * metricIndex); int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue)); @@ -207,7 +204,7 @@ public class PlaybackGraphs { ArrayList<ShapeDrawable> shapes) { // Shapes drawn here are drawn relative to the viewRect Rect viewRect = shapes.get(shapes.size() - 1).getBounds(); - canvas.translate(0, 5 * PlaybackView.TILEY - viewRect.top); + canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top); for (ShapeDrawable shape : mShapes) { shape.draw(canvas); @@ -234,13 +231,15 @@ public class PlaybackGraphs { int yPos = LABELOFFSET; canvas.drawText(label, xPos, yPos, whiteLabels); for (int statIndex = 0; statIndex < Stats.length; statIndex++) { - label = resources.getString(R.string.format_stat, mStats[metricIndex][statIndex]); - yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILEY / 2; + label = resources.getString(R.string.format_stat, + mStats[metricIndex][statIndex]); + yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE + / 2; canvas.drawText(label, xPos, yPos, whiteLabels); } } for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) { - int yPos = LABELOFFSET + stringIndex * PlaybackView.TILEY / 2; + int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2; canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels); } } diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java index f104eac21b89..edc8643e5b24 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java @@ -16,6 +16,9 @@ package com.test.tilebenchmark; +import android.animation.ArgbEvaluator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -30,8 +33,9 @@ import android.view.View; import java.util.ArrayList; public class PlaybackView extends View { - public static final int TILEX = 300; - public static final int TILEY = 300; + public static final int TILE_SCALE = 300; + private static final int INVAL_FLAG = -2; + private static final int INVAL_CYCLE = 250; private Paint levelPaint = null, coordPaint = null, goldPaint = null; private PlaybackGraphs mGraphs; @@ -39,28 +43,46 @@ public class PlaybackView extends View { private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>(); private TileData mProfData[][] = null; private GestureDetector mGestureDetector = null; - private String mRenderStrings[] = new String[3]; + private String mRenderStrings[] = new String[4]; private class TileDrawable extends ShapeDrawable { TileData tile; + String label; - public TileDrawable(TileData t) { - int tileColorId = t.isReady ? R.color.ready_tile - : R.color.unready_tile; - getPaint().setColor(getResources().getColor(tileColorId)); - - setBounds(t.x * TILEX, t.y * TILEY, (t.x + 1) * TILEX, (t.y + 1) - * TILEY); + public TileDrawable(TileData t, int colorId) { this.tile = t; + getPaint().setColor(getResources().getColor(colorId)); + if (colorId == R.color.ready_tile + || colorId == R.color.unready_tile) { + + label = (int) (t.left / TILE_SCALE) + ", " + + (int) (t.top / TILE_SCALE); + // ignore scale value for tiles + setBounds(t.left, t.top, + t.right, t.bottom); + } else { + setBounds((int) (t.left * t.scale), + (int) (t.top * t.scale), + (int) (t.right * t.scale), + (int) (t.bottom * t.scale)); + } + } + + @SuppressWarnings("unused") + public void setColor(int color) { + getPaint().setColor(color); } @Override public void draw(Canvas canvas) { super.draw(canvas); - canvas.drawText(Integer.toString(tile.level), getBounds().left, - getBounds().bottom, levelPaint); - canvas.drawText(tile.x + "," + tile.y, getBounds().left, - ((getBounds().bottom + getBounds().top) / 2), coordPaint); + if (label != null) { + canvas.drawText(Integer.toString(tile.level), getBounds().left, + getBounds().bottom, levelPaint); + canvas.drawText(label, getBounds().left, + ((getBounds().bottom + getBounds().top) / 2), + coordPaint); + } } } @@ -92,10 +114,10 @@ public class PlaybackView extends View { private void init() { levelPaint = new Paint(); levelPaint.setColor(Color.WHITE); - levelPaint.setTextSize(TILEY / 2); + levelPaint.setTextSize(TILE_SCALE / 2); coordPaint = new Paint(); coordPaint.setColor(Color.BLACK); - coordPaint.setTextSize(TILEY / 3); + coordPaint.setTextSize(TILE_SCALE / 3); goldPaint = new Paint(); goldPaint.setColor(0xffa0e010); mGraphs = new PlaybackGraphs(); @@ -110,6 +132,7 @@ public class PlaybackView extends View { } mGraphs.draw(canvas, mTempShapes, mRenderStrings, getResources()); + invalidate(); // may have animations, force redraw } public int setFrame(int frame) { @@ -117,35 +140,66 @@ public class PlaybackView extends View { return 0; } - int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0; + int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0; mTempShapes.clear(); - // draw actual tiles - for (int tileID = 2; tileID < mProfData[frame].length; tileID++) { - TileData t = mProfData[frame][tileID]; - mTempShapes.add(new TileDrawable(t)); - if (t.isReady) { - readyTiles++; + // create tile shapes (as they're drawn on bottom) + for (TileData t : mProfData[frame]) { + if (t.level != INVAL_FLAG && t != mProfData[frame][0]) { + int colorId; + if (t.isReady) { + readyTiles++; + colorId = R.color.ready_tile; + } else { + unreadyTiles++; + colorId = R.color.unready_tile; + } + if (t.left < 0 || t.top < 0) { + unplacedTiles++; + } + mTempShapes.add(new TileDrawable(t, colorId)); } else { - unreadyTiles++; + numInvals++; } - if (t.x < 0 || t.y < 0) { - unplacedTiles++; + } + + // create invalidate shapes (drawn above tiles) + int invalId = 0; + for (TileData t : mProfData[frame]) { + if (t.level == INVAL_FLAG && t != mProfData[frame][0]) { + TileDrawable invalShape = new TileDrawable(t, + R.color.inval_region_start); + ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape, + "color", + getResources().getColor(R.color.inval_region_start), + getResources().getColor(R.color.inval_region_stop)); + tileAnimator.setDuration(numInvals * INVAL_CYCLE); + tileAnimator.setEvaluator(new ArgbEvaluator()); + tileAnimator.setRepeatCount(ValueAnimator.INFINITE); + tileAnimator.setRepeatMode(ValueAnimator.RESTART); + float delay = (float) (invalId) * INVAL_CYCLE; + tileAnimator.setStartDelay((int) delay); + invalId++; + tileAnimator.start(); + + mTempShapes.add(invalShape); } } + mRenderStrings[0] = getResources().getString(R.string.format_stat_name, getResources().getString(R.string.ready_tiles), readyTiles); mRenderStrings[1] = getResources().getString(R.string.format_stat_name, getResources().getString(R.string.unready_tiles), unreadyTiles); mRenderStrings[2] = getResources().getString(R.string.format_stat_name, - getResources().getString(R.string.unplaced_tiles), unplacedTiles); - - // draw view rect (using first two TileData objects) - ShapeDrawable viewShape = new ShapeDrawable(); - viewShape.getPaint().setColor(0xff0000ff); - viewShape.setAlpha(64); - viewShape.setBounds(mProfData[frame][0].x, mProfData[frame][0].y, - mProfData[frame][1].x, mProfData[frame][1].y); + getResources().getString(R.string.unplaced_tiles), + unplacedTiles); + mRenderStrings[3] = getResources().getString(R.string.format_stat_name, + getResources().getString(R.string.number_invalidates), + numInvals); + + // draw view rect (using first TileData object, on top) + TileDrawable viewShape = new TileDrawable(mProfData[frame][0], + R.color.view); mTempShapes.add(viewShape); this.invalidate(); return frame; diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java index 23b62751b931..1521807eb1dc 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java @@ -38,6 +38,7 @@ import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import android.widget.ToggleButton; import java.io.FileOutputStream; import java.io.IOException; @@ -58,11 +59,24 @@ public class ProfileActivity extends Activity { // before test Button mInspectButton; + ToggleButton mCaptureButton; Spinner mVelocitySpinner; + Spinner mMovementSpinner; EditText mUrl; ProfiledWebView mWeb; ProfileCallback mCallback; + LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient(); + AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient(); + + private enum TestingState { + NOT_TESTING, + PRE_TESTING, + START_TESTING, + STOP_TESTING, + SAVED_TESTING + }; + private class VelocitySelectedListener implements OnItemSelectedListener { @Override public void onItemSelected(AdapterView<?> parent, View view, @@ -77,6 +91,31 @@ public class ProfileActivity extends Activity { } } + private class MovementSelectedListener implements OnItemSelectedListener { + @Override + public void onItemSelected(AdapterView<?> parent, View view, + int position, long id) { + String movementStr = parent.getItemAtPosition(position).toString(); + if (movementStr == getResources().getString( + R.string.movement_auto_scroll) + || movementStr == getResources().getString( + R.string.movement_auto_fling)) { + mWeb.setWebViewClient(mAutoLoggingWebViewClient); + mCaptureButton.setEnabled(false); + mVelocitySpinner.setEnabled(true); + } else if (movementStr == getResources().getString( + R.string.movement_manual)) { + mWeb.setWebViewClient(mLoggingWebViewClient); + mCaptureButton.setEnabled(true); + mVelocitySpinner.setEnabled(false); + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + } + } + private class LoggingWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { @@ -88,6 +127,9 @@ public class ProfileActivity extends Activity { super.onPageStarted(view, url, favicon); mUrl.setText(url); } + } + + private class AutoLoggingWebViewClient extends LoggingWebViewClient { @Override public void onPageFinished(WebView view, String url) { @@ -100,10 +142,16 @@ public class ProfileActivity extends Activity { @Override public void onFinish() { - mWeb.startScrollTest(mCallback); + startViewProfiling(true); } }.start(); } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + setTestingState(TestingState.PRE_TESTING); + } } private class StoreFileTask extends @@ -125,24 +173,65 @@ public class ProfileActivity extends Activity { @Override protected void onPostExecute(Void v) { - mUrl.setBackgroundResource(R.color.finished_url); + setTestingState(TestingState.SAVED_TESTING); } } + public void setTestingState(TestingState state) { + switch (state) { + case NOT_TESTING: + mUrl.setBackgroundResource(R.color.background_not_testing); + mInspectButton.setEnabled(true); + mMovementSpinner.setEnabled(true); + break; + case PRE_TESTING: + mInspectButton.setEnabled(false); + mMovementSpinner.setEnabled(false); + break; + case START_TESTING: + mUrl.setBackgroundResource(R.color.background_start_testing); + mInspectButton.setEnabled(false); + mMovementSpinner.setEnabled(false); + break; + case STOP_TESTING: + mUrl.setBackgroundResource(R.color.background_stop_testing); + break; + case SAVED_TESTING: + mInspectButton.setEnabled(true); + mMovementSpinner.setEnabled(true); + break; + } + } + + /** auto - automatically scroll. */ + private void startViewProfiling(boolean auto) { + if (!auto) { + // manual, toggle capture button to indicate capture state to user + mCaptureButton.setChecked(true); + } + mWeb.startScrollTest(mCallback, auto); + setTestingState(TestingState.START_TESTING); + } + /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mInspectButton = (Button) findViewById(R.id.inspect); + mCaptureButton = (ToggleButton) findViewById(R.id.capture); mVelocitySpinner = (Spinner) findViewById(R.id.velocity); + mMovementSpinner = (Spinner) findViewById(R.id.movement); mUrl = (EditText) findViewById(R.id.url); mWeb = (ProfiledWebView) findViewById(R.id.web); mCallback = new ProfileCallback() { @SuppressWarnings("unchecked") @Override public void profileCallback(TileData[][] data) { - new StoreFileTask().execute(new Pair<String, TileData[][]>(TEMP_FILENAME, data)); + new StoreFileTask().execute(new Pair<String, TileData[][]>( + TEMP_FILENAME, data)); + mCaptureButton.setChecked(false); + setTestingState(TestingState.STOP_TESTING); } }; @@ -166,6 +255,33 @@ public class ProfileActivity extends Activity { new VelocitySelectedListener()); mVelocitySpinner.setSelection(3); + // Movement spinner + String content[] = { + getResources().getString(R.string.movement_auto_scroll), + getResources().getString(R.string.movement_auto_fling), + getResources().getString(R.string.movement_manual) + }; + adapter = new ArrayAdapter<CharSequence>(this, + android.R.layout.simple_spinner_item, content); + adapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mMovementSpinner.setAdapter(adapter); + mMovementSpinner.setOnItemSelectedListener( + new MovementSelectedListener()); + mMovementSpinner.setSelection(0); + + // Capture toggle button + mCaptureButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mCaptureButton.isChecked()) { + startViewProfiling(false); + } else { + mWeb.stopScrollTest(); + } + } + }); + // Custom profiling WebView WebSettings settings = mWeb.getSettings(); settings.setJavaScriptEnabled(true); @@ -180,12 +296,13 @@ public class ProfileActivity extends Activity { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { String url = mUrl.getText().toString(); - mUrl.setBackgroundResource(R.color.unfinished_url); mWeb.loadUrl(url); mWeb.requestFocus(); return true; } }); + + setTestingState(TestingState.NOT_TESTING); } public void setCallback(ProfileCallback callback) { diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java index 656062421b97..d3941be41302 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java @@ -59,12 +59,13 @@ public class ProfiledWebView extends WebView { } /* - * Called once the page is loaded to start scrolling for evaluating tiles + * Called once the page is loaded to start scrolling for evaluating tiles. + * If autoScrolling isn't set, stop must be called manually. */ - public void startScrollTest(ProfileCallback callback) { - isScrolling = true; + public void startScrollTest(ProfileCallback callback, boolean autoScrolling) { + isScrolling = autoScrolling; mCallback = callback; - super.tileProfilingStart(); + tileProfilingStart(); invalidate(); } @@ -72,19 +73,31 @@ public class ProfiledWebView extends WebView { * Called once the page has stopped scrolling */ public void stopScrollTest() { - float testRatio = super.tileProfilingStop(); + super.tileProfilingStop(); + + if (mCallback == null) { + tileProfilingClear(); + return; + } TileData data[][] = new TileData[super.tileProfilingNumFrames()][]; for (int frame = 0; frame < data.length; frame++) { data[frame] = new TileData[ - super.tileProfilingNumTilesInFrame(frame)]; + tileProfilingNumTilesInFrame(frame)]; for (int tile = 0; tile < data[frame].length; tile++) { - int x = super.tileProfilingGetX(frame, tile); - int y = super.tileProfilingGetY(frame, tile); - boolean isReady = super.tileProfilingGetReady(frame, tile); - int level = super.tileProfilingGetLevel(frame, tile); + int left = tileProfilingGetInt(frame, tile, "left"); + int top = tileProfilingGetInt(frame, tile, "top"); + int right = tileProfilingGetInt(frame, tile, "right"); + int bottom = tileProfilingGetInt(frame, tile, "bottom"); + + boolean isReady = super.tileProfilingGetInt( + frame, tile, "isReady") == 1; + int level = tileProfilingGetInt(frame, tile, "level"); + + float scale = tileProfilingGetFloat(frame, tile, "scale"); - data[frame][tile] = new TileData(x, y, isReady, level); + data[frame][tile] = new TileData(left, top, right, bottom, + isReady, level, scale); } } super.tileProfilingClear(); diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java index 7d4bb9f5217f..3e729a6282be 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java @@ -19,14 +19,24 @@ package com.test.tilebenchmark; import java.io.Serializable; public class TileData implements Serializable { - public int x, y; + int left, top, right, bottom; public boolean isReady; public int level; + public float scale; - public TileData(int x, int y, boolean isReady, int level) { - this.x = x; - this.y = y; + public TileData(int left, int top, int right, int bottom, boolean isReady, + int level, float scale) { + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; this.isReady = isReady; this.level = level; + this.scale = scale; + } + + public String toString() { + return "Tile (" + left + "," + top + ")->(" + + right + "," + bottom + ")"; } } diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 6e13d0fb349c..f1f0fcc6ac9f 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -104,18 +104,30 @@ public class WifiNative { public native static boolean stopDriverCommand(); + + /** + * Start filtering out Multicast V4 packets + * @return {@code true} if the operation succeeded, {@code false} otherwise + */ + public native static boolean startFilteringMulticastV4Packets(); + + /** + * Stop filtering out Multicast V4 packets. + * @return {@code true} if the operation succeeded, {@code false} otherwise + */ + public native static boolean stopFilteringMulticastV4Packets(); + /** - * Start filtering out multicast packets, to reduce battery consumption - * that would result from processing them, only to discard them. + * Start filtering out Multicast V6 packets * @return {@code true} if the operation succeeded, {@code false} otherwise */ - public native static boolean startPacketFiltering(); + public native static boolean startFilteringMulticastV6Packets(); /** - * Stop filtering out multicast packets. + * Stop filtering out Multicast V6 packets. * @return {@code true} if the operation succeeded, {@code false} otherwise */ - public native static boolean stopPacketFiltering(); + public native static boolean stopFilteringMulticastV6Packets(); public native static boolean setPowerModeCommand(int mode); diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 12efeb1e59f1..f08bb6a2e5ea 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -82,6 +82,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; /** @@ -160,6 +161,9 @@ public class WifiStateMachine extends StateMachine { /* Tracks current frequency mode */ private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); + /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ + private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); + // Channel for sending replies. private AsyncChannel mReplyChannel = new AsyncChannel(); @@ -285,6 +289,11 @@ public class WifiStateMachine extends StateMachine { static final int CMD_START_PACKET_FILTERING = BASE + 84; /* Clear packet filter */ static final int CMD_STOP_PACKET_FILTERING = BASE + 85; + + /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ + static final int MULTICAST_V6 = 1; + static final int MULTICAST_V4 = 0; + /* Connect to a specified network (network id * or WifiConfiguration) This involves increasing * the priority of the network, enabling the network @@ -868,17 +877,33 @@ public class WifiStateMachine extends StateMachine { } /** - * Start packet filtering + * Start filtering Multicast v4 packets + */ + public void startFilteringMulticastV4Packets() { + mFilteringMulticastV4Packets.set(true); + sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0)); + } + + /** + * Stop filtering Multicast v4 packets + */ + public void stopFilteringMulticastV4Packets() { + mFilteringMulticastV4Packets.set(false); + sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0)); + } + + /** + * Start filtering Multicast v4 packets */ - public void startPacketFiltering() { - sendMessage(CMD_START_PACKET_FILTERING); + public void startFilteringMulticastV6Packets() { + sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0)); } /** - * Stop packet filtering + * Stop filtering Multicast v4 packets */ - public void stopPacketFiltering() { - sendMessage(CMD_STOP_PACKET_FILTERING); + public void stopFilteringMulticastV6Packets() { + sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0)); } /** @@ -2074,9 +2099,6 @@ public class WifiStateMachine extends StateMachine { WifiConfigStore.initialize(mContext); - //TODO: initialize and fix multicast filtering - //mWM.initializeMulticastFiltering(); - sendSupplicantConnectionChangedBroadcast(true); transitionTo(mDriverStartedState); break; @@ -2359,6 +2381,16 @@ public class WifiStateMachine extends StateMachine { /* initialize network state */ setNetworkDetailedState(DetailedState.DISCONNECTED); + /* Remove any filtering on Multicast v6 at start */ + WifiNative.stopFilteringMulticastV6Packets(); + + /* Reset Multicast v4 filtering state */ + if (mFilteringMulticastV4Packets.get()) { + WifiNative.startFilteringMulticastV4Packets(); + } else { + WifiNative.stopFilteringMulticastV4Packets(); + } + if (mIsScanMode) { WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); WifiNative.disconnectCommand(); @@ -2419,10 +2451,22 @@ public class WifiStateMachine extends StateMachine { mWakeLock.release(); break; case CMD_START_PACKET_FILTERING: - WifiNative.startPacketFiltering(); + if (message.arg1 == MULTICAST_V6) { + WifiNative.startFilteringMulticastV6Packets(); + } else if (message.arg1 == MULTICAST_V4) { + WifiNative.startFilteringMulticastV4Packets(); + } else { + Log.e(TAG, "Illegal arugments to CMD_START_PACKET_FILTERING"); + } break; case CMD_STOP_PACKET_FILTERING: - WifiNative.stopPacketFiltering(); + if (message.arg1 == MULTICAST_V6) { + WifiNative.stopFilteringMulticastV6Packets(); + } else if (message.arg1 == MULTICAST_V4) { + WifiNative.stopFilteringMulticastV4Packets(); + } else { + Log.e(TAG, "Illegal arugments to CMD_STOP_PACKET_FILTERING"); + } break; default: return NOT_HANDLED; |