Merge "Respect android:allowBackup="false" during full backup & restore"
diff --git a/api/current.txt b/api/current.txt
index edce92a..8ef07de 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -97,6 +97,7 @@
     field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
     field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
     field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
+    field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
     field public static final deprecated java.lang.String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
     field public static final java.lang.String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
     field public static final java.lang.String SET_TIME = "android.permission.SET_TIME";
@@ -179,9 +180,9 @@
   public static final class R.attr {
     ctor public R.attr();
     field public static final int absListViewStyle = 16842858; // 0x101006a
-    field public static final int accessibilityEventTypes = 16843645; // 0x101037d
-    field public static final int accessibilityFeedbackType = 16843647; // 0x101037f
-    field public static final int accessibilityFlags = 16843649; // 0x1010381
+    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
@@ -201,7 +202,7 @@
     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 = 16843643; // 0x101037b
+    field public static final int actionModeSelectAllDrawable = 16843645; // 0x101037d
     field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
     field public static final int actionViewClass = 16843516; // 0x10102fc
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -273,7 +274,7 @@
     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 = 16843650; // 0x1010382
+    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
@@ -306,9 +307,9 @@
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
-    field public static final int columnCount = 16843635; // 0x1010373
+    field public static final int columnCount = 16843636; // 0x1010374
     field public static final int columnDelay = 16843215; // 0x10101cf
-    field public static final int columnOrderPreserved = 16843636; // 0x1010374
+    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
@@ -453,7 +454,7 @@
     field public static final int fromXScale = 16843202; // 0x10101c2
     field public static final int fromYDelta = 16843208; // 0x10101c8
     field public static final int fromYScale = 16843204; // 0x10101c4
-    field public static final int fullBackupAgent = 16843631; // 0x101036f
+    field public static final int fullBackupAgent = 16843632; // 0x1010370
     field public static final int fullBright = 16842954; // 0x10100ca
     field public static final int fullDark = 16842950; // 0x10100c6
     field public static final int functionalTest = 16842787; // 0x1010023
@@ -484,7 +485,7 @@
     field public static final int hint = 16843088; // 0x1010150
     field public static final int homeAsUpIndicator = 16843531; // 0x101030b
     field public static final int homeLayout = 16843549; // 0x101031d
-    field public static final int horizontalDirection = 16843630; // 0x101036e
+    field public static final int horizontalDirection = 16843631; // 0x101036f
     field public static final int horizontalDivider = 16843053; // 0x101012d
     field public static final int horizontalGap = 16843327; // 0x101023f
     field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
@@ -532,7 +533,7 @@
     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 = 16843644; // 0x101037c
+    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
@@ -564,6 +565,7 @@
     field public static final int labelTextSize = 16843317; // 0x1010235
     field public static final int largeHeap = 16843610; // 0x101035a
     field public static final int largeScreens = 16843398; // 0x1010286
+    field public static final int largestWidthLimitDp = 16843622; // 0x1010366
     field public static final int launchMode = 16842781; // 0x101001d
     field public static final int layerType = 16843604; // 0x1010354
     field public static final int layout = 16842994; // 0x10100f2
@@ -584,8 +586,8 @@
     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_columnSpan = 16843641; // 0x1010379
-    field public static final int layout_columnWeight = 16843642; // 0x101037a
+    field public static final int layout_columnSpan = 16843643; // 0x101037b
+    field public static final int layout_columnWeight = 16843644; // 0x101037c
     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
@@ -593,9 +595,9 @@
     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 = 16843638; // 0x1010376
-    field public static final int layout_rowSpan = 16843639; // 0x1010377
-    field public static final int layout_rowWeight = 16843640; // 0x1010378
+    field public static final int layout_row = 16843640; // 0x1010378
+    field public static final int layout_rowSpan = 16843641; // 0x1010379
+    field public static final int layout_rowWeight = 16843642; // 0x101037a
     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
@@ -625,6 +627,7 @@
     field public static final int loopViews = 16843527; // 0x1010307
     field public static final int manageSpaceActivity = 16842756; // 0x1010004
     field public static final int mapViewStyle = 16842890; // 0x101008a
+    field public static final int marginsIncludedInAlignment = 16843639; // 0x1010377
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
     field public static final int max = 16843062; // 0x1010136
     field public static final int maxDate = 16843584; // 0x1010340
@@ -661,7 +664,7 @@
     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 = 16843648; // 0x1010380
+    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
@@ -678,7 +681,7 @@
     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 = 16843646; // 0x101037e
+    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
@@ -768,11 +771,11 @@
     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 = 16843633; // 0x1010371
+    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 = 16843634; // 0x1010372
+    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
@@ -859,14 +862,14 @@
     field public static final int state_active = 16842914; // 0x10100a2
     field public static final int state_checkable = 16842911; // 0x101009f
     field public static final int state_checked = 16842912; // 0x10100a0
-    field public static final int state_drag_can_accept = 16843623; // 0x1010367
-    field public static final int state_drag_hovered = 16843624; // 0x1010368
+    field public static final int state_drag_can_accept = 16843624; // 0x1010368
+    field public static final int state_drag_hovered = 16843625; // 0x1010369
     field public static final int state_empty = 16842921; // 0x10100a9
     field public static final int state_enabled = 16842910; // 0x101009e
     field public static final int state_expanded = 16842920; // 0x10100a8
     field public static final int state_first = 16842916; // 0x10100a4
     field public static final int state_focused = 16842908; // 0x101009c
-    field public static final int state_hovered = 16843622; // 0x1010366
+    field public static final int state_hovered = 16843623; // 0x1010367
     field public static final int state_last = 16842918; // 0x10100a6
     field public static final int state_long_pressable = 16843324; // 0x101023c
     field public static final int state_middle = 16842917; // 0x10100a5
@@ -877,7 +880,7 @@
     field public static final int state_window_focused = 16842909; // 0x101009d
     field public static final int staticWallpaperPreview = 16843569; // 0x1010331
     field public static final int stepSize = 16843078; // 0x1010146
-    field public static final int stopWithTask = 16843625; // 0x1010369
+    field public static final int stopWithTask = 16843626; // 0x101036a
     field public static final int streamType = 16843273; // 0x1010209
     field public static final int stretchColumns = 16843081; // 0x1010149
     field public static final int stretchMode = 16843030; // 0x1010116
@@ -885,7 +888,7 @@
     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 = 16843632; // 0x1010370
+    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
@@ -953,9 +956,9 @@
     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 = 16843629; // 0x101036d
-    field public static final int textEditSuggestionsBottomWindowLayout = 16843627; // 0x101036b
-    field public static final int textEditSuggestionsTopWindowLayout = 16843628; // 0x101036c
+    field public static final int textEditSuggestionItemLayout = 16843630; // 0x101036e
+    field public static final int textEditSuggestionsBottomWindowLayout = 16843628; // 0x101036c
+    field public static final int textEditSuggestionsTopWindowLayout = 16843629; // 0x101036d
     field public static final int textFilterEnabled = 16843007; // 0x10100ff
     field public static final int textIsSelectable = 16843542; // 0x1010316
     field public static final int textOff = 16843045; // 0x1010125
@@ -967,7 +970,7 @@
     field public static final int textSelectHandleWindowStyle = 16843464; // 0x10102c8
     field public static final int textSize = 16842901; // 0x1010095
     field public static final int textStyle = 16842903; // 0x1010097
-    field public static final int textSuggestionsWindowStyle = 16843626; // 0x101036a
+    field public static final int textSuggestionsWindowStyle = 16843627; // 0x101036b
     field public static final int textViewStyle = 16842884; // 0x1010084
     field public static final int theme = 16842752; // 0x1010000
     field public static final int thickness = 16843360; // 0x1010260
@@ -1003,7 +1006,7 @@
     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 = 16843637; // 0x1010375
+    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
@@ -2890,6 +2893,7 @@
     method public void registerForContextMenu(android.view.View);
     method public void setArguments(android.os.Bundle);
     method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(android.app.Fragment.SavedState);
     method public void setRetainInstance(boolean);
     method public void setTargetFragment(android.app.Fragment, int);
     method public void startActivity(android.content.Intent);
@@ -2901,6 +2905,12 @@
     ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
   }
 
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.ClassLoaderCreator CREATOR;
+  }
+
   public class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
     ctor public FragmentBreadCrumbs(android.content.Context);
     ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet);
@@ -2938,6 +2948,7 @@
     method public abstract boolean popBackStackImmediate(int, int);
     method public abstract void putFragment(android.os.Bundle, java.lang.String, android.app.Fragment);
     method public abstract void removeOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.app.Fragment.SavedState saveFragmentInstanceState(android.app.Fragment);
     field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
   }
 
@@ -5507,6 +5518,7 @@
     field public int descriptionRes;
     field public boolean enabled;
     field public int flags;
+    field public int largestWidthLimitDp;
     field public java.lang.String manageSpaceActivityName;
     field public java.lang.String nativeLibraryDir;
     field public java.lang.String permission;
@@ -14160,6 +14172,10 @@
     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
   }
 
+  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
+    method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
+  }
+
   public static abstract interface Parcelable.Creator {
     method public abstract T createFromParcel(android.os.Parcel);
     method public abstract T[] newArray(int);
@@ -23398,6 +23414,7 @@
     method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
     method public void onRequestFocus(android.webkit.WebView);
     method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback);
+    method public void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
   }
 
   public static abstract interface WebChromeClient.CustomViewCallback {
@@ -24533,6 +24550,7 @@
     ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
     ctor public GridLayout(android.content.Context, android.util.AttributeSet);
     method public int getColumnCount();
+    method public boolean getMarginsIncludedInAlignment();
     method public int getOrientation();
     method public int getRowCount();
     method public boolean getUseDefaultMargins();
@@ -24541,6 +24559,7 @@
     method protected void onLayout(boolean, int, int, int, int);
     method public void setColumnCount(int);
     method public void setColumnOrderPreserved(boolean);
+    method public void setMarginsIncludedInAlignment(boolean);
     method public void setOrientation(int);
     method public void setRowCount(int);
     method public void setRowOrderPreserved(boolean);
@@ -24553,6 +24572,7 @@
     field public static final android.widget.GridLayout.Alignment LEFT;
     field public static final android.widget.GridLayout.Alignment RIGHT;
     field public static final android.widget.GridLayout.Alignment TOP;
+    field public static final int UNDEFINED = -2147483648; // 0x80000000
     field public static final int VERTICAL = 1; // 0x1
   }
 
@@ -24562,17 +24582,9 @@
   }
 
   public static class GridLayout.Group {
-    ctor public GridLayout.Group(android.widget.GridLayout.Interval, android.widget.GridLayout.Alignment);
     ctor public GridLayout.Group(int, int, android.widget.GridLayout.Alignment);
     ctor public GridLayout.Group(int, android.widget.GridLayout.Alignment);
     field public final android.widget.GridLayout.Alignment alignment;
-    field public final android.widget.GridLayout.Interval span;
-  }
-
-  public static class GridLayout.Interval {
-    ctor public GridLayout.Interval(int, int);
-    field public final int max;
-    field public final int min;
   }
 
   public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7e20c75..7e94cf2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -172,6 +172,11 @@
     // These can be accessed by multiple threads; mPackages is the lock.
     // XXX For now we keep around information about all packages we have
     // seen, not removing entries from this map.
+    // NOTE: The activity manager in its process needs to call in to
+    // ActivityThread to do things like update resource configurations,
+    // which means this lock gets held while the activity manager holds its
+    // own lock.  Thus you MUST NEVER call back into the activity manager
+    // or anything that depends on it while holding this lock.
     final HashMap<String, WeakReference<LoadedApk>> mPackages
             = new HashMap<String, WeakReference<LoadedApk>>();
     final HashMap<String, WeakReference<LoadedApk>> mResourcePackages
@@ -1489,7 +1494,7 @@
     }
 
     public Configuration getConfiguration() {
-        return mConfiguration;
+        return mResConfiguration;
     }
 
     public boolean isProfiling() {
@@ -1534,7 +1539,7 @@
         synchronized (this) {
             ContextImpl context = getSystemContext();
             context.init(new LoadedApk(this, "android", context, info,
-                    new CompatibilityInfo(info, 0, 0, false)), null, this);
+                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this);
         }
     }
 
@@ -1879,7 +1884,7 @@
             }
             deliverNewIntents(r, intents);
             if (resumed) {
-                mInstrumentation.callActivityOnResume(r.activity);
+                r.activity.performResume();
                 r.activity.mTemporaryPause = false;
             }
         }
@@ -2845,7 +2850,7 @@
             }
             deliverResults(r, res.results);
             if (resumed) {
-                mInstrumentation.callActivityOnResume(r.activity);
+                r.activity.performResume();
                 r.activity.mTemporaryPause = false;
             }
         }
@@ -3270,7 +3275,7 @@
                 // If this activity doesn't handle any of the config changes
                 // then don't bother calling onConfigurationChanged as we're
                 // going to destroy it.
-                if ((~activity.mActivityInfo.configChanges & diff) == 0) {
+                if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
                     shouldChangeConfig = true;
                 }
             }
@@ -3293,6 +3298,12 @@
         }
     }
 
+    public final void applyConfigurationToResources(Configuration config) {
+        synchronized (mPackages) {
+            applyConfigurationToResourcesLocked(config, null);
+        }
+    }
+
     final boolean applyConfigurationToResourcesLocked(Configuration config,
             CompatibilityInfo compat) {
         if (mResConfiguration == null) {
@@ -3518,8 +3529,7 @@
          * reflect configuration changes. The configuration object passed
          * in AppBindData can be safely assumed to be up to date
          */
-        Resources.getSystem().updateConfiguration(mConfiguration,
-                Resources.getSystem().getDisplayMetrics(), data.compatInfo);
+        applyConfigurationToResourcesLocked(data.config, data.compatInfo);
 
         data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
 
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 6f0bbd7..14ffd3b 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -450,6 +450,51 @@
     boolean mCheckedForLoaderManager;
     
     /**
+     * State information that has been retrieved from a fragment instance
+     * through {@link FragmentManager#saveFragmentInstanceState(Fragment)
+     * FragmentManager.saveFragmentInstanceState}.
+     */
+    public static class SavedState implements Parcelable {
+        final Bundle mState;
+
+        SavedState(Bundle state) {
+            mState = state;
+        }
+
+        SavedState(Parcel in, ClassLoader loader) {
+            mState = in.readBundle();
+            if (loader != null && mState != null) {
+                mState.setClassLoader(loader);
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeBundle(mState);
+        }
+
+        public static final Parcelable.ClassLoaderCreator<SavedState> CREATOR
+                = new Parcelable.ClassLoaderCreator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    /**
      * Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when
      * there is an instantiation failure.
      */
@@ -624,6 +669,22 @@
     }
 
     /**
+     * Set the initial saved state that this Fragment should restore itself
+     * from when first being constructed, as returned by
+     * {@link FragmentManager#saveFragmentInstanceState(Fragment)
+     * FragmentManager.saveFragmentInstanceState}.
+     *
+     * @param state The state the fragment should be restored from.
+     */
+    public void setInitialSavedState(SavedState state) {
+        if (mIndex >= 0) {
+            throw new IllegalStateException("Fragment already active");
+        }
+        mSavedFragmentState = state != null && state.mState != null
+                ? state.mState : null;
+    }
+
+    /**
      * Optional target for this fragment.  This may be used, for example,
      * if this fragment is being started by another, and when done wants to
      * give a result back to the first.  The target set here is retained
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0da656f..2164ada 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -274,6 +274,30 @@
     public abstract Fragment getFragment(Bundle bundle, String key);
 
     /**
+     * Save the current instance state of the given Fragment.  This can be
+     * used later when creating a new instance of the Fragment and adding
+     * it to the fragment manager, to have it create itself to match the
+     * current state returned here.  Note that there are limits on how
+     * this can be used:
+     *
+     * <ul>
+     * <li>The Fragment must currently be attached to the FragmentManager.
+     * <li>A new Fragment created using this saved state must be the same class
+     * type as the Fragment it was created from.
+     * <li>The saved state can not contain dependencies on other fragments --
+     * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to
+     * store a fragment reference because that reference may not be valid when
+     * this saved state is later used.  Likewise the Fragment's target and
+     * result code are not included in this state.
+     * </ul>
+     *
+     * @param f The Fragment whose state is to be saved.
+     * @return The generated state.  This will be null if there was no
+     * interesting state created by the fragment.
+     */
+    public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
+
+    /**
      * Print the FragmentManager's state into the given stream.
      *
      * @param prefix Text to print at the front of each line.
@@ -492,6 +516,19 @@
     }
 
     @Override
+    public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
+        if (fragment.mIndex < 0) {
+            throw new IllegalStateException("Fragment " + fragment
+                    + " is not currently in the FragmentManager");
+        }
+        if (fragment.mState > Fragment.INITIALIZING) {
+            Bundle result = saveFragmentBasicState(fragment);
+            return result != null ? new Fragment.SavedState(result) : null;
+        }
+        return null;
+    }
+
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(128);
         sb.append("FragmentManager{");
@@ -715,7 +752,6 @@
                         if (f.mView != null) {
                             f.mView.setSaveFromParentEnabled(false);
                             if (f.mHidden) f.mView.setVisibility(View.GONE);
-                            f.restoreViewState();
                             f.onViewCreated(f.mView, f.mSavedFragmentState);
                         }
                     }
@@ -747,7 +783,6 @@
                                     container.addView(f.mView);
                                 }
                                 if (f.mHidden) f.mView.setVisibility(View.GONE);
-                                f.restoreViewState();
                                 f.onViewCreated(f.mView, f.mSavedFragmentState);
                             }
                         }
@@ -759,6 +794,7 @@
                                     + " did not call through to super.onActivityCreated()");
                         }
                         if (f.mView != null) {
+                            f.restoreViewState();
                         }
                         f.mSavedFragmentState = null;
                     }
@@ -1375,6 +1411,8 @@
         }
         if (mStateArray == null) {
             mStateArray = new SparseArray<Parcelable>();
+        } else {
+            mStateArray.clear();
         }
         f.mView.saveHierarchyState(mStateArray);
         if (mStateArray.size() > 0) {
@@ -1383,6 +1421,32 @@
         }
     }
     
+    Bundle saveFragmentBasicState(Fragment f) {
+        Bundle result = null;
+
+        if (mStateBundle == null) {
+            mStateBundle = new Bundle();
+        }
+        f.onSaveInstanceState(mStateBundle);
+        if (!mStateBundle.isEmpty()) {
+            result = mStateBundle;
+            mStateBundle = null;
+        }
+
+        if (f.mView != null) {
+            saveFragmentViewState(f);
+            if (f.mSavedViewState != null) {
+                if (result == null) {
+                    result = new Bundle();
+                }
+                result.putSparseParcelableArray(
+                        FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
+            }
+        }
+
+        return result;
+    }
+
     Parcelable saveAllState() {
         // Make sure all pending operations have now been executed to get
         // our state update-to-date.
@@ -1407,25 +1471,7 @@
                 active[i] = fs;
                 
                 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
-                    if (mStateBundle == null) {
-                        mStateBundle = new Bundle();
-                    }
-                    f.onSaveInstanceState(mStateBundle);
-                    if (!mStateBundle.isEmpty()) {
-                        fs.mSavedFragmentState = mStateBundle;
-                        mStateBundle = null;
-                    }
-
-                    if (f.mView != null) {
-                        saveFragmentViewState(f);
-                        if (f.mSavedViewState != null) {
-                            if (fs.mSavedFragmentState == null) {
-                                fs.mSavedFragmentState = new Bundle();
-                            }
-                            fs.mSavedFragmentState.putSparseParcelableArray(
-                                    FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
-                        }
-                    }
+                    fs.mSavedFragmentState = saveFragmentBasicState(f);
 
                     if (f.mTarget != null) {
                         if (f.mTarget.mIndex < 0) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 5307696..6287d33 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -98,6 +98,12 @@
         return mApplication;
     }
 
+    /**
+     * Create information about a new .apk
+     *
+     * NOTE: This constructor is called with ActivityThread's lock held,
+     * so MUST NOT call back out to the activity manager.
+     */
     public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
             CompatibilityInfo compatInfo,
             ActivityThread mainThread, ClassLoader baseLoader,
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4285388..4858f14 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -335,13 +335,25 @@
     /**
      * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle the screen size. Set from the
-     * {@link android.R.attr#configChanges} attribute.
+     * {@link android.R.attr#configChanges} attribute.  This will be
+     * set by default for applications that target an earlier version
+     * than {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}...
+     * <b>however</b>, you will not see the bit set here becomes some
+     * applications incorrectly compare {@link #configChanges} against
+     * an absolute value rather than correctly masking out the bits
+     * they are interested in.  Please don't do that, thanks.
      */
     public static final int CONFIG_SCREEN_SIZE = 0x0400;
     /**
      * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle the smallest screen size. Set from the
-     * {@link android.R.attr#configChanges} attribute.
+     * {@link android.R.attr#configChanges} attribute.  This will be
+     * set by default for applications that target an earlier version
+     * than {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}...
+     * <b>however</b>, you will not see the bit set here becomes some
+     * applications incorrectly compare {@link #configChanges} against
+     * an absolute value rather than correctly masking out the bits
+     * they are interested in.  Please don't do that, thanks.
      */
     public static final int CONFIG_SMALLEST_SCREEN_SIZE = 0x0800;
     /**
@@ -386,6 +398,21 @@
     }
 
     /**
+     * @hide
+     * Unfortunately some developers (OpenFeint I am looking at you) have
+     * compared the configChanges bit field against absolute values, so if we
+     * introduce a new bit they break.  To deal with that, we will make sure
+     * the public field will not have a value that breaks them, and let the
+     * framework call here to get the real value.
+     */
+    public int getRealConfigChanged() {
+        return applicationInfo.targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB_MR2
+                ? (configChanges | ActivityInfo.CONFIG_SCREEN_SIZE
+                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE)
+                : configChanges;
+    }
+
+    /**
      * Bit mask of kinds of configuration changes that this activity
      * can handle itself (without being restarted by the system).
      * Contains any combination of {@link #CONFIG_FONT_SCALE},
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ccd3567..c0a1d8e 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -346,6 +346,14 @@
     public int compatibleWidthLimitDp = 0;
 
     /**
+     * The maximum smallest screen width the application will work on.  If 0,
+     * nothing has been specified.  Comes from
+     * {@link android.R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
+     * android:largestWidthLimitDp} attribute of the &lt;supports-screens&gt; tag.
+     */
+    public int largestWidthLimitDp = 0;
+
+    /**
      * Full path to the location of this package.
      */
     public String sourceDir;
@@ -427,7 +435,8 @@
         pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
                 + " theme=0x" + Integer.toHexString(theme));
         pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
-                + " compatibleWidthLimitDp=" + compatibleWidthLimitDp);
+                + " compatibleWidthLimitDp=" + compatibleWidthLimitDp
+                + " largestWidthLimitDp=" + largestWidthLimitDp);
         pw.println(prefix + "sourceDir=" + sourceDir);
         if (sourceDir == null) {
             if (publicSourceDir != null) {
@@ -489,6 +498,7 @@
         flags = orig.flags;
         requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
         compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
+        largestWidthLimitDp = orig.largestWidthLimitDp;
         sourceDir = orig.sourceDir;
         publicSourceDir = orig.publicSourceDir;
         nativeLibraryDir = orig.nativeLibraryDir;
@@ -524,6 +534,7 @@
         dest.writeInt(flags);
         dest.writeInt(requiresSmallestWidthDp);
         dest.writeInt(compatibleWidthLimitDp);
+        dest.writeInt(largestWidthLimitDp);
         dest.writeString(sourceDir);
         dest.writeString(publicSourceDir);
         dest.writeString(nativeLibraryDir);
@@ -560,6 +571,7 @@
         flags = source.readInt();
         requiresSmallestWidthDp = source.readInt();
         compatibleWidthLimitDp = source.readInt();
+        largestWidthLimitDp = source.readInt();
         sourceDir = source.readString();
         publicSourceDir = source.readString();
         nativeLibraryDir = source.readString();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5f9a957..09fede0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -999,6 +999,9 @@
                 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
                         0);
+                pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
+                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
+                        0);
 
                 // This is a trick to get a boolean and still able to detect
                 // if a value was actually set.
@@ -1948,11 +1951,6 @@
             a.info.configChanges = sa.getInt(
                     com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
                     0);
-            if (owner.applicationInfo.targetSdkVersion
-                        < android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
-                a.info.configChanges |= ActivityInfo.CONFIG_SCREEN_SIZE
-                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
-            }
             a.info.softInputMode = sa.getInt(
                     com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
                     0);
diff --git a/core/java/android/content/res/CompatibilityInfo.aidl b/core/java/android/content/res/CompatibilityInfo.aidl
new file mode 100644
index 0000000..cde3d7b
--- /dev/null
+++ b/core/java/android/content/res/CompatibilityInfo.aidl
@@ -0,0 +1,20 @@
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+package android.content.res;
+
+parcelable CompatibilityInfo;
+
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index e42caca..b686e54 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -96,21 +96,42 @@
             boolean forceCompat) {
         int compatFlags = 0;
 
-        if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0) {
+        if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0
+                || appInfo.largestWidthLimitDp != 0) {
             // New style screen requirements spec.
             int required = appInfo.requiresSmallestWidthDp != 0
                     ? appInfo.requiresSmallestWidthDp
                     : appInfo.compatibleWidthLimitDp;
+            if (required == 0) {
+                required = appInfo.largestWidthLimitDp;
+            }
             int compat = appInfo.compatibleWidthLimitDp != 0
-                    ? appInfo.compatibleWidthLimitDp
-                    : appInfo.requiresSmallestWidthDp;
+                    ? appInfo.compatibleWidthLimitDp : required;
             if (compat < required)  {
                 compat = required;
             }
+            int largest = appInfo.largestWidthLimitDp;
 
-            if (compat >= sw) {
+            if (required > DEFAULT_NORMAL_SHORT_DIMENSION) {
+                // For now -- if they require a size larger than the only
+                // size we can do in compatibility mode, then don't ever
+                // allow the app to go in to compat mode.  Trying to run
+                // it at a smaller size it can handle will make it far more
+                // broken than running at a larger size than it wants or
+                // thinks it can handle.
+                compatFlags |= NEVER_NEEDS_COMPAT;
+            } else if (largest != 0 && sw > largest) {
+                // If the screen size is larger than the largest size the
+                // app thinks it can work with, then always force it in to
+                // compatibility mode.
+                compatFlags |= NEEDS_SCREEN_COMPAT | ALWAYS_NEEDS_COMPAT;
+            } else if (compat >= sw) {
+                // The screen size is something the app says it was designed
+                // for, so never do compatibility mode.
                 compatFlags |= NEVER_NEEDS_COMPAT;
             } else if (forceCompat) {
+                // The app may work better with or without compatibility mode.
+                // Let the user decide.
                 compatFlags |= NEEDS_SCREEN_COMPAT;
             }
 
@@ -199,6 +220,9 @@
                 } else if (!anyResizeable) {
                     compatFlags |= ALWAYS_NEEDS_COMPAT;
                 }
+            } else {
+                compatFlags &= ~NEEDS_SCREEN_COMPAT;
+                compatFlags |= NEVER_NEEDS_COMPAT;
             }
 
             if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
@@ -243,11 +267,11 @@
     }
     
     public boolean neverSupportsScreen() {
-        return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0;
+        return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0;
     }
 
     public boolean alwaysSupportsScreen() {
-        return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0;
+        return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0;
     }
 
     /**
@@ -406,7 +430,7 @@
         if (!supportsScreen()) {
             // This is a larger screen device and the app is not
             // compatible with large screens, so diddle it.
-            CompatibilityInfo.updateCompatibleScreenFrame(inoutDm, null, inoutDm);
+            CompatibilityInfo.computeCompatibleScaling(inoutDm, inoutDm);
         } else {
             inoutDm.widthPixels = inoutDm.unscaledWidthPixels;
             inoutDm.heightPixels = inoutDm.unscaledHeightPixels;
@@ -443,8 +467,7 @@
      * @param outRect the output parameter which will contain the result.
      * @return Returns the scaling factor for the window.
      */
-    public static float updateCompatibleScreenFrame(DisplayMetrics dm,
-            Rect outRect, DisplayMetrics outDm) {
+    public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) {
         final int width = dm.unscaledWidthPixels;
         final int height = dm.unscaledHeightPixels;
         int shortSize, longSize;
@@ -477,12 +500,6 @@
             scale = 1;
         }
 
-        if (outRect != null) {
-            final int left = (int)((width-(newWidth*scale))/2);
-            final int top = (int)((height-(newHeight*scale))/2);
-            outRect.set(left, top, left+newWidth, top+newHeight);
-        }
-
         if (outDm != null) {
             outDm.widthPixels = newWidth;
             outDm.heightPixels = newHeight;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index d476997..6409aac 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -330,17 +330,17 @@
         if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
             sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
         } else {
-            sb.append("?swdp");
+            sb.append(" ?swdp");
         }
         if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
             sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
         } else {
-            sb.append("?wdp");
+            sb.append(" ?wdp");
         }
         if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
             sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
         } else {
-            sb.append("?hdp");
+            sb.append(" ?hdp");
         }
         switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
             case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 81dc46a..70bf524 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -28,14 +28,13 @@
 import android.graphics.drawable.Drawable.ConstantState;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.util.LongSparseArray;
-import android.view.Display;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -1406,6 +1405,12 @@
     public void updateConfiguration(Configuration config,
             DisplayMetrics metrics, CompatibilityInfo compat) {
         synchronized (mTmpValue) {
+            if (false) {
+                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
+                        + mConfiguration + " old compat is " + mCompatibilityInfo);
+                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
+                        + config + " new compat is " + compat);
+            }
             if (compat != null) {
                 mCompatibilityInfo = compat;
             }
@@ -1471,6 +1476,11 @@
                     mConfiguration.screenLayout, mConfiguration.uiMode,
                     Build.VERSION.RESOURCES_SDK_INT);
 
+            if (false) {
+                Slog.i(TAG, "**** Updating config of " + this + ": final config is " + mConfiguration
+                        + " final compat is " + mCompatibilityInfo);
+            }
+
             clearDrawableCache(mDrawableCache, configChanges);
             clearDrawableCache(mColorDrawableCache, configChanges);
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9accf99..d7bbab6 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -233,6 +233,16 @@
         
         /**
          * Current development version.
+         *
+         * <p>Update to Honeycomb MR1 to support 7 inch tablets, improve
+         * screen compatibility mode, etc.</p>
+         *
+         * <p>As of this version, applications that don't say whether they
+         * support XLARGE screens will be assumed to do so only if they target
+         * {@link #HONEYCOMB} or later; it had been {@link #GINGERBREAD} or
+         * later.  Applications that don't support a screen size at least as
+         * large as the current screen will provide the user with a UI to
+         * switch them in to screen size compatibility mode.</p>
          */
         public static final int HONEYCOMB_MR2 = CUR_DEVELOPMENT;
 
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 6b35215..e9ed676 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1980,6 +1980,9 @@
             }
         }
 
+        if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+            return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
+        }
         return creator.createFromParcel(this);
     }
 
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index 0a4b60f..594fbb2 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -113,4 +113,22 @@
          */
         public T[] newArray(int size);
     }
+
+    /**
+     * Specialization of {@link Creator} that allows you to receive the
+     * ClassLoader the object is being created in.
+     */
+    public interface ClassLoaderCreator<T> extends Creator<T> {
+        /**
+         * Create a new instance of the Parcelable class, instantiating it
+         * from the given Parcel whose data had previously been written by
+         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()} and
+         * using the given ClassLoader.
+         *
+         * @param source The Parcel to read the object's data from.
+         * @param loader The ClassLoader that this object is being created in.
+         * @return Returns a new instance of the Parcelable class.
+         */
+        public T createFromParcel(Parcel source, ClassLoader loader);
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c78b935..893947d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1809,6 +1809,16 @@
         public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
 
         /**
+         * Pointer speed setting.
+         * This is an integer value in a range between -7 and +7, so there are 15 possible values.
+         *   -7 = slowest
+         *    0 = default speed
+         *   +7 = fastest
+         * @hide
+         */
+        public static final String POINTER_SPEED = "pointer_speed";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          * @hide
@@ -1872,6 +1882,7 @@
             USE_PTP_INTERFACE,
             SIP_CALL_OPTIONS,
             SIP_RECEIVE_CALLS,
+            POINTER_SPEED,
         };
 
         // Settings moved to Settings.Secure
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 717dde8..ddd3252 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -55,6 +55,8 @@
 
     private CallbackMap mCallbacks;
 
+    private int mDefaultAvailability = TextToSpeech.LANG_NOT_SUPPORTED;
+
     @Override
     public void onCreate() {
         if (DBG) Log.d(TAG, "onCreate()");
@@ -71,7 +73,8 @@
         mCallbacks = new CallbackMap();
 
         // Load default language
-        onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
+        mDefaultAvailability = onLoadLanguage(getDefaultLanguage(),
+                getDefaultCountry(), getDefaultVariant());
     }
 
     @Override
@@ -651,17 +654,43 @@
             return onGetLanguage();
         }
 
+        /*
+         * If defaults are enforced, then no language is "available" except
+         * perhaps the default language selected by the user.
+         */
         public int isLanguageAvailable(String lang, String country, String variant) {
+            if (areDefaultsEnforced()) {
+                if (isDefault(lang, country, variant)) {
+                    return mDefaultAvailability;
+                } else {
+                    return TextToSpeech.LANG_NOT_SUPPORTED;
+                }
+            }
             return onIsLanguageAvailable(lang, country, variant);
         }
 
+        /*
+         * There is no point loading a non default language if defaults
+         * are enforced.
+         */
         public int loadLanguage(String lang, String country, String variant) {
+            if (areDefaultsEnforced()) {
+                if (isDefault(lang, country, variant)) {
+                    return mDefaultAvailability;
+                } else {
+                    return TextToSpeech.LANG_NOT_SUPPORTED;
+                }
+            }
             return onLoadLanguage(lang, country, variant);
         }
 
         public void setCallback(String packageName, ITextToSpeechCallback cb) {
             mCallbacks.setCallback(packageName, cb);
         }
+
+        private boolean isDefault(String lang, String country, String variant) {
+            return Locale.getDefault().equals(new Locale(lang, country, variant));
+        }
     };
 
     private class CallbackMap extends RemoteCallbackList<ITextToSpeechCallback> {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bdf04ab0..ad17edf 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -19,6 +19,7 @@
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Point;
@@ -88,7 +89,7 @@
     void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim);
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
-            CharSequence nonLocalizedLabel, int labelRes,
+            in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppWillBeHidden(IBinder token);
     void setAppVisibility(IBinder token, boolean visible);
@@ -204,4 +205,9 @@
      * Called by the status bar to notify Views of changes to System UI visiblity.
      */
     void statusBarVisibilityChanged(int visibility);
+
+    /**
+     * Called by the settings application to temporarily set the pointer speed.
+     */
+    void setPointerSpeed(int speed);
 }
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index bd33a6a..1e72529 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -765,10 +765,17 @@
             fullRedrawNeeded = true;
             mLayoutRequested = true;
 
-            DisplayMetrics packageMetrics =
-                mView.getContext().getResources().getDisplayMetrics();
-            desiredWindowWidth = packageMetrics.widthPixels;
-            desiredWindowHeight = packageMetrics.heightPixels;
+            if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
+                // NOTE -- system code, won't try to do compat mode.
+                Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
+                desiredWindowWidth = disp.getRealWidth();
+                desiredWindowHeight = disp.getRealHeight();
+            } else {
+                DisplayMetrics packageMetrics =
+                    mView.getContext().getResources().getDisplayMetrics();
+                desiredWindowWidth = packageMetrics.widthPixels;
+                desiredWindowHeight = packageMetrics.heightPixels;
+            }
 
             // For the very first time, tell the view hierarchy that it
             // is attached to the window.  Note that at this point the surface
@@ -912,9 +919,16 @@
                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     windowSizeMayChange = true;
 
-                    DisplayMetrics packageMetrics = res.getDisplayMetrics();
-                    desiredWindowWidth = packageMetrics.widthPixels;
-                    desiredWindowHeight = packageMetrics.heightPixels;
+                    if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
+                        // NOTE -- system code, won't try to do compat mode.
+                        Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
+                        desiredWindowWidth = disp.getRealWidth();
+                        desiredWindowHeight = disp.getRealHeight();
+                    } else {
+                        DisplayMetrics packageMetrics = res.getDisplayMetrics();
+                        desiredWindowWidth = packageMetrics.widthPixels;
+                        desiredWindowHeight = packageMetrics.heightPixels;
+                    }
                 }
             }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 82a4d2d..8a30c7b 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.content.Context;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -539,7 +540,7 @@
      * @see #removeStartingWindow
      */
     public View addStartingWindow(IBinder appToken, String packageName,
-            int theme, CharSequence nonLocalizedLabel,
+            int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel,
             int labelRes, int icon, int windowFlags);
 
     /**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index ea66d67..4df237b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1024,13 +1024,13 @@
                 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
                         + ic + " tba=" + tba + " initial=" + initial);
                 InputBindResult res = mService.startInput(mClient,
-                        servedContext, tba, initial, mCurMethod == null);
+                        servedContext, tba, initial, true);
                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
                 if (res != null) {
                     if (res.id != null) {
                         mBindSequence = res.sequence;
                         mCurMethod = res.method;
-                    } else {
+                    } else if (mCurMethod == null) {
                         // This means there is no input method available.
                         if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
                         return;
diff --git a/core/java/android/webkit/PluginFullScreenHolder.java b/core/java/android/webkit/PluginFullScreenHolder.java
index ae326d5..42ba7c9 100644
--- a/core/java/android/webkit/PluginFullScreenHolder.java
+++ b/core/java/android/webkit/PluginFullScreenHolder.java
@@ -24,34 +24,44 @@
  */
 package android.webkit;
 
-import android.app.Dialog;
+import android.content.Context;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
 
-class PluginFullScreenHolder extends Dialog {
+class PluginFullScreenHolder {
 
     private final WebView mWebView;
     private final int mNpp;
+    private final int mOrientation;
+
+    // The container for the plugin view
+    private static CustomFrameLayout mLayout;
+
     private View mContentView;
 
-    PluginFullScreenHolder(WebView webView, int npp) {
-        super(webView.getContext(), android.R.style.Theme_NoTitleBar_Fullscreen);
+    PluginFullScreenHolder(WebView webView, int orientation, int npp) {
         mWebView = webView;
         mNpp = npp;
+        mOrientation = orientation;
     }
 
-    @Override
     public void setContentView(View contentView) {
-        // as we are sharing the View between full screen and
-        // embedded mode, we have to remove the
-        // AbsoluteLayout.LayoutParams set by embedded mode to
-        // ViewGroup.LayoutParams before adding it to the dialog
-        contentView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
+
+        // Create a FrameLayout that will contain the plugin's view
+        mLayout = new CustomFrameLayout(mWebView.getContext());
+        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            Gravity.CENTER);
+
+        mLayout.addView(contentView, layoutParams);
+        mLayout.setVisibility(View.VISIBLE);
+
         // fixed size is only used either during pinch zoom or surface is too
         // big. Make sure it is not fixed size before setting it to the full
         // screen content view. The SurfaceView will be set to the correct mode
@@ -62,59 +72,79 @@
                 sView.getHolder().setSizeFromLayout();
             }
         }
-        super.setContentView(contentView);
+
         mContentView = contentView;
     }
 
-    @Override
-    public void onBackPressed() {
-        mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
-                .sendToTarget();
+    public void show() {
+        // Other plugins may attempt to draw so hide them while we're active.
+        if (mWebView.getViewManager() != null)
+            mWebView.getViewManager().hideAll();
+
+        WebChromeClient client = mWebView.getWebChromeClient();
+        client.onShowCustomView(mLayout, mOrientation, mCallback);
     }
 
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (event.isSystem()) {
-            return super.onKeyDown(keyCode, event);
+    public void hide() {
+        WebChromeClient client = mWebView.getWebChromeClient();
+        client.onHideCustomView();
+    }
+
+    private class CustomFrameLayout extends FrameLayout {
+
+        CustomFrameLayout(Context context) {
+            super(context);
         }
-        mWebView.onKeyDown(keyCode, event);
-        // always return true as we are the handler
-        return true;
-    }
 
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (event.isSystem()) {
-            return super.onKeyUp(keyCode, event);
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            if (event.isSystem()) {
+                return super.onKeyDown(keyCode, event);
+            }
+            mWebView.onKeyDown(keyCode, event);
+            // always return true as we are the handler
+            return true;
         }
-        mWebView.onKeyUp(keyCode, event);
-        // always return true as we are the handler
-        return true;
-    }
 
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        // always return true as we don't want the event to propagate any further
-        return true;
-    }
-
-    @Override
-    public boolean onTrackballEvent(MotionEvent event) {
-        mWebView.onTrackballEvent(event);
-        // always return true as we are the handler
-        return true;
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        // manually remove the contentView's parent since the dialog does not
-        if (mContentView != null && mContentView.getParent() != null) {
-            ViewGroup vg = (ViewGroup) mContentView.getParent();
-            vg.removeView(mContentView);
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (event.isSystem()) {
+                return super.onKeyUp(keyCode, event);
+            }
+            mWebView.onKeyUp(keyCode, event);
+            // always return true as we are the handler
+            return true;
         }
-        mWebView.getWebViewCore().sendMessage(
-                WebViewCore.EventHub.HIDE_FULLSCREEN, mNpp, 0);
-    }
 
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            // always return true as we don't want the event to propagate any further
+            return true;
+        }
+
+        @Override
+        public boolean onTrackballEvent(MotionEvent event) {
+            mWebView.onTrackballEvent(event);
+            // always return true as we are the handler
+            return true;
+        }
+    }
+    
+    private final WebChromeClient.CustomViewCallback mCallback =
+        new WebChromeClient.CustomViewCallback() {
+            public void onCustomViewHidden() {
+
+                mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
+                    .sendToTarget();
+
+                mWebView.getWebViewCore().sendMessage(
+                        WebViewCore.EventHub.HIDE_FULLSCREEN, mNpp, 0);
+
+                mLayout.removeView(mContentView);
+                mLayout = null;
+
+                // Re enable plugin views.
+                mWebView.getViewManager().showAll();
+            }
+        };
 }
diff --git a/core/java/android/webkit/ViewStateSerializer.java b/core/java/android/webkit/ViewStateSerializer.java
new file mode 100644
index 0000000..0fc76fa
--- /dev/null
+++ b/core/java/android/webkit/ViewStateSerializer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.webkit;
+
+import android.graphics.Point;
+import android.graphics.Region;
+import android.webkit.WebViewCore.DrawData;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @hide
+ */
+class ViewStateSerializer {
+
+    private static final int WORKING_STREAM_STORAGE = 16 * 1024;
+
+    static final int VERSION = 1;
+
+    static boolean serializeViewState(OutputStream stream, WebView web)
+            throws IOException {
+        DataOutputStream dos = new DataOutputStream(stream);
+        dos.writeInt(VERSION);
+        dos.writeInt(web.getContentWidth());
+        dos.writeInt(web.getContentHeight());
+        return nativeSerializeViewState(web.getBaseLayer(), dos,
+                new byte[WORKING_STREAM_STORAGE]);
+    }
+
+    static DrawData deserializeViewState(InputStream stream, WebView web)
+            throws IOException {
+        DataInputStream dis = new DataInputStream(stream);
+        int version = dis.readInt();
+        if (version != VERSION) {
+            throw new IOException("Unexpected version: " + version);
+        }
+        int contentWidth = dis.readInt();
+        int contentHeight = dis.readInt();
+        int baseLayer = nativeDeserializeViewState(dis,
+                new byte[WORKING_STREAM_STORAGE]);
+
+        final WebViewCore.DrawData draw = new WebViewCore.DrawData();
+        draw.mViewState = new WebViewCore.ViewState();
+        int viewWidth = web.getViewWidth();
+        int viewHeight = web.getViewHeightWithTitle() - web.getTitleHeight();
+        draw.mViewSize = new Point(viewWidth, viewHeight);
+        draw.mContentSize = new Point(contentWidth, contentHeight);
+        draw.mViewState.mDefaultScale = web.getDefaultZoomScale();
+        draw.mBaseLayer = baseLayer;
+        draw.mInvalRegion = new Region(0, 0, contentWidth, contentHeight);
+        return draw;
+    }
+
+    private static native boolean nativeSerializeViewState(int baseLayer,
+            OutputStream stream, byte[] storage);
+
+    // Returns a pointer to the BaseLayer
+    private static native int nativeDeserializeViewState(
+            InputStream stream, byte[] storage);
+
+    private ViewStateSerializer() {}
+}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 755366c..ae40ded 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Message;
@@ -77,6 +78,18 @@
 
     /**
      * Notify the host application that the current page would
+     * like to show a custom View in a particular orientation.
+     * @param view is the View object to be shown.
+     * @param requestedOrientation An orientation constant as used in
+     * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
+     * @param callback is the callback to be invoked if and when the view
+     * is dismissed.
+     */
+    public void onShowCustomView(View view, int requestedOrientation,
+            CustomViewCallback callback) {};
+    
+    /**
+     * Notify the host application that the current page would
      * like to hide its custom view.
      */
     public void onHideCustomView() {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3c2c8f6..9e61ecf 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -84,6 +84,7 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebTextView.AutoCompleteAdapter;
+import android.webkit.WebViewCore.DrawData;
 import android.webkit.WebViewCore.EventHub;
 import android.webkit.WebViewCore.TouchEventData;
 import android.webkit.WebViewCore.TouchHighlightData;
@@ -102,6 +103,9 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -616,6 +620,9 @@
     // SetBaseLayer time and to pause when WebView paused.
     private HTML5VideoViewProxy mHTML5VideoViewProxy;
 
+    // If we are using a set picture, don't send view updates to webkit
+    private boolean mBlockWebkitViewMessages = false;
+
     /*
      * Private message ids
      */
@@ -1400,7 +1407,7 @@
         return getViewHeightWithTitle() - getVisibleTitleHeight();
     }
 
-    private int getViewHeightWithTitle() {
+    int getViewHeightWithTitle() {
         int height = getHeight();
         if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) {
             height -= getHorizontalScrollbarHeight();
@@ -1786,6 +1793,52 @@
     }
 
     /**
+     * Saves the view data to the output stream. The output is highly
+     * version specific, and may not be able to be loaded by newer versions
+     * of WebView.
+     * @param stream The {@link OutputStream} to save to
+     * @return True if saved successfully
+     * @hide
+     */
+    public boolean saveViewState(OutputStream stream) {
+        try {
+            return ViewStateSerializer.serializeViewState(stream, this);
+        } catch (IOException e) {
+            Log.w(LOGTAG, "Failed to saveViewState", e);
+        }
+        return false;
+    }
+
+    /**
+     * Loads the view data from the input stream. See
+     * {@link #saveViewState(OutputStream)} for more information.
+     * @param stream The {@link InputStream} to load from
+     * @return True if loaded successfully
+     * @hide
+     */
+    public boolean loadViewState(InputStream stream) {
+        try {
+            DrawData draw = ViewStateSerializer.deserializeViewState(stream, this);
+            mBlockWebkitViewMessages = true;
+            setNewPicture(draw);
+            return true;
+        } catch (IOException e) {
+            Log.w(LOGTAG, "Failed to loadViewState", e);
+        }
+        return false;
+    }
+
+    /**
+     * Clears the view state set with {@link #loadViewState(InputStream)}.
+     * This WebView will then switch to showing the content from webkit
+     * @hide
+     */
+    public void clearViewState() {
+        mBlockWebkitViewMessages = false;
+        invalidate();
+    }
+
+    /**
      * Restore the state of this WebView from the given map used in
      * {@link android.app.Activity#onRestoreInstanceState}. This method should
      * be called to restore the state of the WebView before using the object. If
@@ -2664,10 +2717,12 @@
         calcOurContentVisibleRect(rect);
         // Rect.equals() checks for null input.
         if (!rect.equals(mLastVisibleRectSent)) {
-            Point pos = new Point(rect.left, rect.top);
-            mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET);
-            mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
-                    nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, pos);
+            if (!mBlockWebkitViewMessages) {
+                Point pos = new Point(rect.left, rect.top);
+                mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET);
+                mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
+                        nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, pos);
+            }
             mLastVisibleRectSent = rect;
             mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
         }
@@ -2682,7 +2737,9 @@
             // TODO: the global offset is only used by windowRect()
             // in ChromeClientAndroid ; other clients such as touch
             // and mouse events could return view + screen relative points.
-            mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect);
+            if (!mBlockWebkitViewMessages) {
+                mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect);
+            }
             mLastGlobalRect = globalRect;
         }
         return rect;
@@ -2747,6 +2804,7 @@
      * @return true if new values were sent
      */
     boolean sendViewSizeZoom(boolean force) {
+        if (mBlockWebkitViewMessages) return false;
         if (mZoomManager.isPreventingWebkitUpdates()) return false;
 
         int viewWidth = getViewWidth();
@@ -3359,9 +3417,11 @@
                 }
                 abortAnimation();
                 mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
-                WebViewCore.resumePriority();
-                if (!mSelectingText) {
-                    WebViewCore.resumeUpdatePicture(mWebViewCore);
+                if (!mBlockWebkitViewMessages) {
+                    WebViewCore.resumePriority();
+                    if (!mSelectingText) {
+                        WebViewCore.resumeUpdatePicture(mWebViewCore);
+                    }
                 }
                 if (oldX != mScrollX || oldY != mScrollY) {
                     sendOurVisibleRect();
@@ -4192,6 +4252,10 @@
         }
     }
 
+    int getBaseLayer() {
+        return nativeGetBaseLayer();
+    }
+
     private void onZoomAnimationStart() {
         // If it is in password mode, turn it off so it does not draw misplaced.
         if (inEditingMode() && nativeFocusCandidateIsPassword()) {
@@ -4215,7 +4279,7 @@
     }
 
     void onFixedLengthZoomAnimationEnd() {
-        if (!mSelectingText) {
+        if (!mBlockWebkitViewMessages && !mSelectingText) {
             WebViewCore.resumeUpdatePicture(mWebViewCore);
         }
         onZoomAnimationEnd();
@@ -4316,7 +4380,7 @@
             // synchronization problem with layers.
             int content = nativeDraw(canvas, color, extras, false);
             canvas.setDrawFilter(null);
-            if (content != 0) {
+            if (!mBlockWebkitViewMessages && content != 0) {
                 mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
             }
         }
@@ -4720,6 +4784,9 @@
 
     @Override
     public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+        if (mBlockWebkitViewMessages) {
+            return false;
+        }
         // send complex characters to webkit for use by JS and plugins
         if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getCharacters() != null) {
             // pass the key to DOM
@@ -4744,6 +4811,9 @@
                     + "keyCode=" + keyCode
                     + ", " + event + ", unicode=" + event.getUnicodeChar());
         }
+        if (mBlockWebkitViewMessages) {
+            return false;
+        }
 
         // don't implement accelerator keys here; defer to host application
         if (event.isCtrlPressed()) {
@@ -4947,6 +5017,9 @@
             Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
                     + ", " + event + ", unicode=" + event.getUnicodeChar());
         }
+        if (mBlockWebkitViewMessages) {
+            return false;
+        }
 
         if (mNativeClass == 0) {
             return false;
@@ -5531,10 +5604,12 @@
     }
 
     private boolean shouldForwardTouchEvent() {
-        return mFullScreenHolder != null || (mForwardTouchEvents
+        if (mFullScreenHolder != null) return true;
+        if (mBlockWebkitViewMessages) return false;
+        return mForwardTouchEvents
                 && !mSelectingText
                 && mPreventDefault != PREVENT_DEFAULT_IGNORE
-                && mPreventDefault != PREVENT_DEFAULT_NO);
+                && mPreventDefault != PREVENT_DEFAULT_NO;
     }
 
     private boolean inFullScreenMode() {
@@ -5543,7 +5618,7 @@
 
     private void dismissFullScreenMode() {
         if (inFullScreenMode()) {
-            mFullScreenHolder.dismiss();
+            mFullScreenHolder.hide();
             mFullScreenHolder = null;
         }
     }
@@ -5665,25 +5740,31 @@
                         // commit the short press action for the previous tap
                         doShortPress();
                         mTouchMode = TOUCH_INIT_MODE;
-                        mDeferTouchProcess = (!inFullScreenMode()
-                                && mForwardTouchEvents) ? hitFocusedPlugin(
-                                contentX, contentY) : false;
+                        mDeferTouchProcess = !mBlockWebkitViewMessages
+                                && (!inFullScreenMode() && mForwardTouchEvents)
+                                ? hitFocusedPlugin(contentX, contentY)
+                                : false;
                     }
                 } else { // the normal case
                     mTouchMode = TOUCH_INIT_MODE;
-                    mDeferTouchProcess = (!inFullScreenMode()
-                            && mForwardTouchEvents) ? hitFocusedPlugin(
-                            contentX, contentY) : false;
-                    mWebViewCore.sendMessage(
-                            EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
+                    mDeferTouchProcess = !mBlockWebkitViewMessages
+                            && (!inFullScreenMode() && mForwardTouchEvents)
+                            ? hitFocusedPlugin(contentX, contentY)
+                            : false;
+                    if (!mBlockWebkitViewMessages) {
+                        mWebViewCore.sendMessage(
+                                EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
+                    }
                     if (getSettings().supportTouchOnly()) {
                         TouchHighlightData data = new TouchHighlightData();
                         data.mX = contentX;
                         data.mY = contentY;
                         data.mSlop = viewToContentDimension(mNavSlop);
-                        mWebViewCore.sendMessageDelayed(
-                                EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data,
-                                ViewConfiguration.getTapTimeout());
+                        if (!mBlockWebkitViewMessages) {
+                            mWebViewCore.sendMessageDelayed(
+                                    EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data,
+                                    ViewConfiguration.getTapTimeout());
+                        }
                         if (DEBUG_TOUCH_HIGHLIGHT) {
                             if (getSettings().getNavDump()) {
                                 mTouchHighlightX = (int) x + mScrollX;
@@ -5719,7 +5800,7 @@
                             SWITCH_TO_LONGPRESS, LONG_PRESS_TIMEOUT);
                     if (inFullScreenMode() || mDeferTouchProcess) {
                         mPreventDefault = PREVENT_DEFAULT_YES;
-                    } else if (mForwardTouchEvents) {
+                    } else if (!mBlockWebkitViewMessages && mForwardTouchEvents) {
                         mPreventDefault = PREVENT_DEFAULT_MAYBE_YES;
                     } else {
                         mPreventDefault = PREVENT_DEFAULT_NO;
@@ -7831,6 +7912,10 @@
                 // after WebView's destroy() is called, skip handling messages.
                 return;
             }
+            if (mBlockWebkitViewMessages) {
+                // Blocking messages from webkit
+                return;
+            }
             switch (msg.what) {
                 case REMEMBER_PASSWORD: {
                     mDatabase.setUsernamePassword(
@@ -7966,66 +8051,7 @@
                 case NEW_PICTURE_MSG_ID: {
                     // called for new content
                     final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
-                    WebViewCore.ViewState viewState = draw.mViewState;
-                    boolean isPictureAfterFirstLayout = viewState != null;
-                    setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
-                            getSettings().getShowVisualIndicator(),
-                            isPictureAfterFirstLayout);
-                    final Point viewSize = draw.mViewSize;
-                    if (isPictureAfterFirstLayout) {
-                        // Reset the last sent data here since dealing with new page.
-                        mLastWidthSent = 0;
-                        mZoomManager.onFirstLayout(draw);
-                        if (!mDrawHistory) {
-                            // Do not send the scroll event for this particular
-                            // scroll message.  Note that a scroll event may
-                            // still be fired if the user scrolls before the
-                            // message can be handled.
-                            mSendScrollEvent = false;
-                            setContentScrollTo(viewState.mScrollX, viewState.mScrollY);
-                            mSendScrollEvent = true;
-
-                            // As we are on a new page, remove the WebTextView. This
-                            // is necessary for page loads driven by webkit, and in
-                            // particular when the user was on a password field, so
-                            // the WebTextView was visible.
-                            clearTextEntry();
-                        }
-                    }
-
-                    // We update the layout (i.e. request a layout from the
-                    // view system) if the last view size that we sent to
-                    // WebCore matches the view size of the picture we just
-                    // received in the fixed dimension.
-                    final boolean updateLayout = viewSize.x == mLastWidthSent
-                            && viewSize.y == mLastHeightSent;
-                    // Don't send scroll event for picture coming from webkit,
-                    // since the new picture may cause a scroll event to override
-                    // the saved history scroll position.
-                    mSendScrollEvent = false;
-                    recordNewContentSize(draw.mContentSize.x,
-                            draw.mContentSize.y, updateLayout);
-                    mSendScrollEvent = true;
-                    if (DebugFlags.WEB_VIEW) {
-                        Rect b = draw.mInvalRegion.getBounds();
-                        Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
-                                b.left+","+b.top+","+b.right+","+b.bottom+"}");
-                    }
-                    invalidateContentRect(draw.mInvalRegion.getBounds());
-
-                    if (mPictureListener != null) {
-                        mPictureListener.onNewPicture(WebView.this, capturePicture());
-                    }
-
-                    // update the zoom information based on the new picture
-                    mZoomManager.onNewPicture(draw);
-
-                    if (draw.mFocusSizeChanged && inEditingMode()) {
-                        mFocusSizeChanged = true;
-                    }
-                    if (isPictureAfterFirstLayout) {
-                        mViewManager.postReadyToDrawAll();
-                    }
+                    setNewPicture(draw);
                     break;
                 }
                 case WEBCORE_INITIALIZED_MSG_ID:
@@ -8198,16 +8224,15 @@
 
                 case SHOW_FULLSCREEN: {
                     View view = (View) msg.obj;
-                    int npp = msg.arg1;
+                    int orientation = msg.arg1;
+                    int npp = msg.arg2;
 
                     if (inFullScreenMode()) {
                         Log.w(LOGTAG, "Should not have another full screen.");
                         dismissFullScreenMode();
                     }
-                    mFullScreenHolder = new PluginFullScreenHolder(WebView.this, npp);
+                    mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp);
                     mFullScreenHolder.setContentView(view);
-                    mFullScreenHolder.setCancelable(false);
-                    mFullScreenHolder.setCanceledOnTouchOutside(false);
                     mFullScreenHolder.show();
 
                     break;
@@ -8345,6 +8370,69 @@
         }
     }
 
+    void setNewPicture(final WebViewCore.DrawData draw) {
+        WebViewCore.ViewState viewState = draw.mViewState;
+        boolean isPictureAfterFirstLayout = viewState != null;
+        setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
+                getSettings().getShowVisualIndicator(),
+                isPictureAfterFirstLayout);
+        final Point viewSize = draw.mViewSize;
+        if (isPictureAfterFirstLayout) {
+            // Reset the last sent data here since dealing with new page.
+            mLastWidthSent = 0;
+            mZoomManager.onFirstLayout(draw);
+            if (!mDrawHistory) {
+                // Do not send the scroll event for this particular
+                // scroll message.  Note that a scroll event may
+                // still be fired if the user scrolls before the
+                // message can be handled.
+                mSendScrollEvent = false;
+                setContentScrollTo(viewState.mScrollX, viewState.mScrollY);
+                mSendScrollEvent = true;
+
+                // As we are on a new page, remove the WebTextView. This
+                // is necessary for page loads driven by webkit, and in
+                // particular when the user was on a password field, so
+                // the WebTextView was visible.
+                clearTextEntry();
+            }
+        }
+
+        // We update the layout (i.e. request a layout from the
+        // view system) if the last view size that we sent to
+        // WebCore matches the view size of the picture we just
+        // received in the fixed dimension.
+        final boolean updateLayout = viewSize.x == mLastWidthSent
+                && viewSize.y == mLastHeightSent;
+        // Don't send scroll event for picture coming from webkit,
+        // since the new picture may cause a scroll event to override
+        // the saved history scroll position.
+        mSendScrollEvent = false;
+        recordNewContentSize(draw.mContentSize.x,
+                draw.mContentSize.y, updateLayout);
+        mSendScrollEvent = true;
+        if (DebugFlags.WEB_VIEW) {
+            Rect b = draw.mInvalRegion.getBounds();
+            Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
+                    b.left+","+b.top+","+b.right+","+b.bottom+"}");
+        }
+        invalidateContentRect(draw.mInvalRegion.getBounds());
+
+        if (mPictureListener != null) {
+            mPictureListener.onNewPicture(WebView.this, capturePicture());
+        }
+
+        // update the zoom information based on the new picture
+        mZoomManager.onNewPicture(draw);
+
+        if (draw.mFocusSizeChanged && inEditingMode()) {
+            mFocusSizeChanged = true;
+        }
+        if (isPictureAfterFirstLayout) {
+            mViewManager.postReadyToDrawAll();
+        }
+    }
+
     /**
      * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID
      * and UPDATE_TEXT_SELECTION_MSG_ID.  Update the selection of WebTextView.
@@ -9047,6 +9135,7 @@
     private native void     nativeSetHeightCanMeasure(boolean measure);
     private native void     nativeSetBaseLayer(int layer, Region invalRegion,
             boolean showVisualIndicator, boolean isPictureAfterFirstLayout);
+    private native int      nativeGetBaseLayer();
     private native void     nativeShowCursorTimed();
     private native void     nativeReplaceBaseContent(int content);
     private native void     nativeCopyBaseContentToPicture(Picture pict);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 13a9793..16e4571 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2623,14 +2623,15 @@
 
     // called by JNI. PluginWidget function to launch a full-screen view using a
     // View object provided by the plugin class.
-    private void showFullScreenPlugin(ViewManager.ChildView childView, int npp) {
+    private void showFullScreenPlugin(ViewManager.ChildView childView, int orientation, int npp) {
         if (mWebView == null) {
             return;
         }
 
         Message message = mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN);
         message.obj = childView.mView;
-        message.arg1 = npp;
+        message.arg1 = orientation;
+        message.arg2 = npp;
         message.sendToTarget();
     }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 680bb7d..82dd5db 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4661,6 +4661,7 @@
         selectedPos = lookForSelectablePosition(selectedPos, down);
         if (selectedPos >= firstPosition && selectedPos <= getLastVisiblePosition()) {
             mLayoutMode = LAYOUT_SPECIFIC;
+            updateSelectorState();
             setSelectionInt(selectedPos);
             invokeOnItemScrollListener();
         } else {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index d3aa42f..988760d 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -218,15 +218,14 @@
         mShowMore.setClickable(true);
         mShowMore.setOnClickListener(this);
         mShowMore.setFocusable(true);
-        mShowMore.setBackgroundResource(android.R.drawable.list_selector_background);
 
         // Pick up from framework resources instead.
         mDefaultGrpLabel = mContext.getString(R.string.default_permission_group);
         mPermFormat = mContext.getString(R.string.permissions_format);
         mNormalIcon = mContext.getResources().getDrawable(R.drawable.ic_text_dot);
         mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission);
-        mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_maximized);
-        mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_minimized);
+        mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_close_holo_dark);
+        mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_open_holo_dark);
         
         // Set permissions view
         setPermissions(mPermsList);
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 4889101..b99cd7f 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -38,6 +38,8 @@
 import java.util.List;
 import java.util.Map;
 
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
 import static java.lang.Math.max;
 import static java.lang.Math.min;
 
@@ -46,7 +48,7 @@
  * <p>
  * The grid is composed of a set of infinitely thin lines that separate the
  * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced
- * by grid <em>indices</em>. A grid that has <code>N</code> columns
+ * by grid <em>indices</em>. A grid with <code>N</code> columns
  * has <code>N + 1</code> grid indices that run from <code>0</code>
  * through <code>N</code> inclusive. Regardless of how GridLayout is
  * configured, grid index <code>0</code> is fixed to the leading edge of the
@@ -116,16 +118,27 @@
      * The horizontal orientation.
      */
     public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+
     /**
      * The vertical orientation.
      */
     public static final int VERTICAL = LinearLayout.VERTICAL;
 
+    /**
+     * The constant used to indicate that a value is undefined.
+     * Fields can use this value to indicate that their values
+     * have not yet been set. Similarly, methods can return this value
+     * to indicate that there is no suitable value that the implementation
+     * can return.
+     * The value used for the constant (currently {@link Integer#MIN_VALUE}) is
+     * intended to avoid confusion between valid values whose sign may not be known.
+     */
+    public static final int UNDEFINED = Integer.MIN_VALUE;
+
     // Misc constants
 
     private static final String TAG = GridLayout.class.getName();
     private static final boolean DEBUG = false;
-    private static final int UNDEFINED = Integer.MIN_VALUE;
     private static final Paint GRID_PAINT = new Paint();
     private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
     private static final int MIN = 0;
@@ -138,6 +151,9 @@
     private static final int DEFAULT_COUNT = UNDEFINED;
     private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
     private static final boolean DEFAULT_ORDER_PRESERVED = false;
+    private static final boolean DEFAULT_MARGINS_INCLUDED = true;
+    // todo remove this
+    private static final int DEFAULT_CONTAINER_MARGIN = 20;
 
     // TypedArray indices
 
@@ -145,9 +161,16 @@
     private static final int ROW_COUNT = styleable.GridLayout_rowCount;
     private static final int COLUMN_COUNT = styleable.GridLayout_columnCount;
     private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins;
+    private static final int MARGINS_INCLUDED = styleable.GridLayout_marginsIncludedInAlignment;
     private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved;
     private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved;
 
+    // Static initialization
+
+    static {
+        GRID_PAINT.setColor(Color.argb(50, 255, 255, 255));
+    }
+
     // Instance variables
 
     private final Axis mHorizontalAxis = new Axis(true);
@@ -155,9 +178,10 @@
     private boolean mLayoutParamsValid = false;
     private int mOrientation = DEFAULT_ORIENTATION;
     private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
+    private boolean mMarginsIncludedInAlignment = DEFAULT_MARGINS_INCLUDED;
     private int mDefaultGravity = Gravity.NO_GRAVITY;
-    boolean maximizing = false;
-    boolean accommodateBothMinAndMax = false;
+
+    /* package */ boolean accommodateBothMinAndMax = false;
 
     // Constructors
 
@@ -194,6 +218,7 @@
             setColumnCount(a.getInteger(COLUMN_COUNT, DEFAULT_COUNT));
             mOrientation = a.getInteger(ORIENTATION, DEFAULT_ORIENTATION);
             mUseDefaultMargins = a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS);
+            mMarginsIncludedInAlignment = a.getBoolean(MARGINS_INCLUDED, DEFAULT_MARGINS_INCLUDED);
             setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
             setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
         } finally {
@@ -320,10 +345,15 @@
      * to the appropriate layout parameter.
      * <p>
      * When false, the default value of all margins is zero.
+     * <p>
+     * When setting to true, consider setting the value of the
+     * {@link #setMarginsIncludedInAlignment(boolean) marginsIncludedInAlignment}
+     * property to false.
      *
      * @param useDefaultMargins use true to make GridLayout allocate default margins
      *
      * @see #getUseDefaultMargins()
+     * @see #setMarginsIncludedInAlignment(boolean)
      *
      * @see MarginLayoutParams#leftMargin
      * @see MarginLayoutParams#topMargin
@@ -334,6 +364,39 @@
      */
     public void setUseDefaultMargins(boolean useDefaultMargins) {
         mUseDefaultMargins = useDefaultMargins;
+        requestLayout();
+    }
+
+    /**
+     * Returns whether GridLayout aligns the edges of the view or the edges
+     * of the larger rectangle created by extending the view by its associated
+     * margins.
+     *
+     * @see #setMarginsIncludedInAlignment(boolean)
+     *
+     * @return true if alignment is between edges including margins.
+     *
+     * @attr ref android.R.styleable#GridLayout_marginsIncludedInAlignment
+     */
+    public boolean getMarginsIncludedInAlignment() {
+        return mMarginsIncludedInAlignment;
+    }
+
+    /**
+     * When true, the bounds of a view are extended outwards according to its
+     * margins before the edges of the resulting rectangle are aligned.
+     * When false, alignment occurs between the bounds of the view - i.e.
+     * {@link #LEFT} alignment means align the left edges of the view.
+     *
+     * @param marginsIncludedInAlignment true if alignment is between edges including margins.
+     *
+     * @see #getMarginsIncludedInAlignment()
+     *
+     * @attr ref android.R.styleable#GridLayout_marginsIncludedInAlignment
+     */
+    public void setMarginsIncludedInAlignment(boolean marginsIncludedInAlignment) {
+        mMarginsIncludedInAlignment = marginsIncludedInAlignment;
+        requestLayout();
     }
 
     /**
@@ -353,11 +416,9 @@
     /**
      * When this property is <code>false</code>, the default state, GridLayout
      * is at liberty to choose an order that better suits the heights of its children.
-       <p>
-     * When this property is <code>true</code>, GridLayout is forced to place row boundaries
-     * (the {@link Interval#min min} and {@link Interval#max max} values of
-     * a {@link LayoutParams#rowGroup rowGroup}'s {@link Group#span span})
-     * so that they appear in ascending order in the view.
+     <p>
+     * When this property is <code>true</code>, GridLayout is forced to place the row boundaries
+     * so that their associated grid indices are in ascending order in the view.
      * <p>
      * GridLayout implements this specification by creating ordering constraints between
      * the variables that represent the locations of the row boundaries.
@@ -377,6 +438,8 @@
      */
     public void setRowOrderPreserved(boolean rowOrderPreserved) {
         mVerticalAxis.setOrderPreserved(rowOrderPreserved);
+        invalidateStructure();
+        requestLayout();
     }
 
     /**
@@ -396,11 +459,9 @@
     /**
      * When this property is <code>false</code>, the default state, GridLayout
      * is at liberty to choose an order that better suits the widths of its children.
-       <p>
-     * When this property is <code>true</code>, GridLayout is forced to place column boundaries
-     * (the {@link Interval#min min} and {@link Interval#max max} values of
-     * a {@link LayoutParams#columnGroup columnGroup}'s {@link Group#span span})
-     * so that they appear in ascending order in the view.
+     <p>
+     * When this property is <code>true</code>, GridLayout is forced to place the column boundaries
+     * so that their associated grid indices are in ascending order in the view.
      * <p>
      * GridLayout implements this specification by creating ordering constraints between
      * the variables that represent the locations of the column boundaries.
@@ -420,13 +481,11 @@
      */
     public void setColumnOrderPreserved(boolean columnOrderPreserved) {
         mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
+        invalidateStructure();
+        requestLayout();
     }
 
-    private static int compare(int i, int j) {
-        return i < j ? -1 : i > j ? 1 : 0;
-    }
-
-    private static int sum(int[] a) {
+    private static int sum(float[] a) {
         int result = 0;
         for (int i = 0, length = a.length; i < length; i++) {
             result += a[i];
@@ -440,13 +499,12 @@
         // gaps are in the proportion of the golden ratio.
         // To effect this with equal margins at each edge, set each of the
         // four margin values to half this amount.
-        c.measure(0, 0);
         return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2);
     }
 
     private int getDefaultMargin(View c, boolean isAtEdge, boolean leading, boolean horizontal) {
-        // todo remove 20 - use padding here?
-        return isAtEdge ? 20 : getDefaultMargin(c, leading, horizontal);
+        // todo remove DEFAULT_CONTAINER_MARGIN. Use padding? Seek advice on Themes/Styles, etc.
+        return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, leading, horizontal);
     }
 
     private int getDefaultMarginValue(View c, LayoutParams p, boolean leading, boolean horizontal) {
@@ -456,7 +514,7 @@
         Group group = horizontal ? p.columnGroup : p.rowGroup;
         Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
         Interval span = group.span;
-        boolean isAtEdge = leading ? span.min == 0 : span.max == axis.getCount();
+        boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
 
         return getDefaultMargin(c, isAtEdge, leading, horizontal);
     }
@@ -464,8 +522,8 @@
     private int getMargin(View view, boolean leading, boolean horizontal) {
         LayoutParams lp = getLayoutParams(view);
         int margin = horizontal ?
-                leading ? lp.leftMargin : lp.rightMargin :
-                leading ? lp.topMargin : lp.bottomMargin;
+                (leading ? lp.leftMargin : lp.rightMargin) :
+                (leading ? lp.topMargin : lp.bottomMargin);
         return margin == UNDEFINED ? getDefaultMarginValue(view, lp, leading, horizontal) : margin;
     }
 
@@ -475,7 +533,7 @@
 
     private void validateLayoutParams() {
         // install default indices for cells if *none* are defined
-        if (mHorizontalAxis.maxIndex1() == UNDEFINED || mVerticalAxis.maxIndex1() == UNDEFINED) {
+        if (mHorizontalAxis.maxIndex1() == UNDEFINED || (mVerticalAxis.maxIndex1() == UNDEFINED)) {
             boolean horizontal = mOrientation == HORIZONTAL;
             int count = horizontal ? mHorizontalAxis.count : mVerticalAxis.count;
             if (count == UNDEFINED) {
@@ -539,14 +597,17 @@
         mLayoutParamsValid = false;
         mHorizontalAxis.invalidateStructure();
         mVerticalAxis.invalidateStructure();
-
         // This can end up being done twice. But better that than not at all.
         invalidateValues();
     }
 
     private void invalidateValues() {
-        mHorizontalAxis.invalidateValues();
-        mVerticalAxis.invalidateValues();
+        // Need null check because requestLayout() is called in View's initializer,
+        // before we are set up.
+        if (mHorizontalAxis != null && mVerticalAxis != null) {
+            mHorizontalAxis.invalidateValues();
+            mVerticalAxis.invalidateValues();
+        }
     }
 
     private LayoutParams getLayoutParams1(View c) {
@@ -605,10 +666,6 @@
         }
     }
 
-    static {
-        GRID_PAINT.setColor(Color.argb(50, 255, 255, 255));
-    }
-
     // Add/remove
 
     @Override
@@ -643,18 +700,49 @@
 
     // Measurement
 
+    private static int getChildMeasureSpec2(int spec, int padding, int childDimension) {
+        int resultSize;
+        int resultMode;
+
+        if (childDimension >= 0) {
+            resultSize = childDimension;
+            resultMode = EXACTLY;
+        } else {
+            /*
+            using the following lines would replicate the logic of ViewGroup.getChildMeasureSpec()
+
+            int specMode = MeasureSpec.getMode(spec);
+            int specSize = MeasureSpec.getSize(spec);
+            int size = Math.max(0, specSize - padding);
+
+            resultSize = size;
+            resultMode = (specMode == EXACTLY && childDimension == LayoutParams.WRAP_CONTENT) ?
+                    AT_MOST : specMode;
+            */
+            resultSize = 0;
+            resultMode = UNSPECIFIED;
+        }
+        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
+    }
+
+    @Override
+    protected void measureChild(View child, int parentWidthSpec, int parentHeightSpec) {
+        ViewGroup.LayoutParams lp = child.getLayoutParams();
+
+        int childWidthMeasureSpec = getChildMeasureSpec2(parentWidthSpec,
+                mPaddingLeft + mPaddingRight, lp.width);
+        int childHeightMeasureSpec = getChildMeasureSpec2(parentHeightSpec,
+                mPaddingTop + mPaddingBottom, lp.height);
+
+        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+    }
+
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
-        invalidateValues();
-        // int width = MeasureSpec.getSize(widthSpec);
-        // int widthMode = MeasureSpec.getMode(widthSpec);
-        // int height = MeasureSpec.getSize(heightSpec);
-        // int heightMode = MeasureSpec.getMode(heightSpec);
+        measureChildren(widthSpec, heightSpec);
 
-        // todo - handle widthSpec and heightSpec properly
-
-        int computedWidth = getPaddingLeft() + mHorizontalAxis.getPref() + getPaddingRight();
-        int computedHeight = getPaddingTop() + mVerticalAxis.getPref() + getPaddingBottom();
+        int computedWidth = getPaddingLeft() + mHorizontalAxis.getMin() + getPaddingRight();
+        int computedHeight = getPaddingTop() + mVerticalAxis.getMin() + getPaddingBottom();
 
         setMeasuredDimension(
                 resolveSizeAndState(computedWidth, widthSpec, 0),
@@ -662,41 +750,54 @@
     }
 
     private int protect(int alignment) {
-        return alignment == UNDEFINED ? 0 : alignment;
-    }
-
-    private int getLocationIncludingMargin(Axis state, int index, boolean leading) {
-        int margin = leading ? state.leadingMargins[index] : -state.trailingMargins[index];
-        return state.locations[index] + margin;
+        return (alignment == UNDEFINED) ? 0 : alignment;
     }
 
     private int getMeasurement(View c, boolean horizontal, int measurementType) {
-        LayoutParams lp = (LayoutParams) c.getLayoutParams();
-        // First check to see if the user has specified the size.
-        // If so, return the specified size.
-        int size = horizontal ? lp.width : lp.height;
-        if (size >= 0) {
-            return size;
-        }
+        return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
+    }
 
-        // measureChild(c, 0, 0);
-        c.measure(0, 0);// todo work out correct order of events for measurement calls
-        int result = horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
-
-        float weight = horizontal ? lp.columnWeight : lp.rowWeight;
-        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
-        if (weight != 0) {
-            return result + axis.prefSizeOfWeightedComponent;
+    private int getMeasurementIncludingMargin(View c, boolean horizontal, int measurementType) {
+        int result = getMeasurement(c, horizontal, measurementType);
+        if (mMarginsIncludedInAlignment) {
+            int leadingMargin = getMargin(c, true, horizontal);
+            int trailingMargin = getMargin(c, false, horizontal);
+            return result + leadingMargin + trailingMargin;
         }
         return result;
     }
 
-    // Layout container
+    private int getAlignmentValue(Alignment alignment, View c, int dim, boolean horizontal, View c1) {
+        int result = alignment.getAlignmentValue(c, dim);
+        if (mMarginsIncludedInAlignment) {
+            int leadingMargin = getMargin(c1, true, horizontal);
+            return result + leadingMargin;
+        }
+        return result;
+    }
 
     @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+    public void requestLayout() {
+        super.requestLayout();
         invalidateValues();
+    }
 
+    // Layout container
+
+    /**
+     * {@inheritDoc}
+     */
+    /*
+     The layout operation is implemented by delegating the heavy lifting to the
+     to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class.
+     Together they compute the locations of the vertical and horizontal lines of
+     the grid (respectively!).
+
+     This method is then left with the simpler task of applying margins, gravity
+     and sizing to each child view and then placing it in its cell.
+     */
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int targetWidth = r - l;
         int targetHeight = b - t;
 
@@ -710,33 +811,43 @@
 
         for (int i = 0, size = getChildCount(); i < size; i++) {
             View view = getChildAt(i);
-            LayoutParams constraints = getLayoutParams(view);
-            Interval hRange = constraints.columnGroup.span;
-            Interval vRange = constraints.rowGroup.span;
+            LayoutParams lp = getLayoutParams(view);
+            Group columnGroup = lp.columnGroup;
+            Group rowGroup = lp.rowGroup;
 
-            int x1 = getLocationIncludingMargin(mHorizontalAxis, hRange.min, true);
-            int y1 = getLocationIncludingMargin(mVerticalAxis, vRange.min, true);
+            Interval colSpan = columnGroup.span;
+            Interval rowSpan = rowGroup.span;
 
-            int x2 = getLocationIncludingMargin(mHorizontalAxis, hRange.max, false);
-            int y2 = getLocationIncludingMargin(mVerticalAxis, vRange.max, false);
+            int x1 = mHorizontalAxis.getLocationIncludingMargin(view, true, colSpan.min);
+            int y1 = mVerticalAxis.getLocationIncludingMargin(view, true, rowSpan.min);
+
+            int x2 = mHorizontalAxis.getLocationIncludingMargin(view, false, colSpan.max);
+            int y2 = mVerticalAxis.getLocationIncludingMargin(view, false, rowSpan.max);
 
             int cellWidth = x2 - x1;
             int cellHeight = y2 - y1;
 
-            Bounds minMaxX = mHorizontalAxis.getGroupBounds().getValue(i);
-            Bounds minMaxY = mVerticalAxis.getGroupBounds().getValue(i);
-
             int pWidth = getMeasurement(view, true, PRF);
             int pHeight = getMeasurement(view, false, PRF);
 
-            Alignment hAlignment = constraints.columnGroup.alignment;
-            Alignment vAlignment = constraints.rowGroup.alignment;
+            Alignment hAlignment = columnGroup.alignment;
+            Alignment vAlignment = rowGroup.alignment;
 
-            int ddx = protect(hAlignment.getAlignmentValue(null, cellWidth - minMaxX.size()));
-            int ddy = protect(vAlignment.getAlignmentValue(null, cellHeight - minMaxY.size()));
+            int dx, dy;
 
-            int dx = ddx + -minMaxX.below - hAlignment.getAlignmentValue(view, pWidth);
-            int dy = ddy + -minMaxY.below - vAlignment.getAlignmentValue(view, pHeight);
+            if (mMarginsIncludedInAlignment) {
+                dx = protect(hAlignment.getAlignmentValue(view, cellWidth - pWidth));
+                dy = protect(vAlignment.getAlignmentValue(view, cellHeight - pHeight));
+            } else {
+                Bounds colBounds = mHorizontalAxis.getGroupBounds().getValue(i);
+                Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
+
+                int mx = protect(hAlignment.getAlignmentValue(null, cellWidth - colBounds.size()));
+                int my = protect(vAlignment.getAlignmentValue(null, cellHeight - rowBounds.size()));
+
+                dx = mx + -colBounds.below - hAlignment.getAlignmentValue(view, pWidth);
+                dy = my + -rowBounds.below - vAlignment.getAlignmentValue(view, pHeight);
+            }
 
             int width = hAlignment.getSizeInCell(view, pWidth, cellWidth);
             int height = vAlignment.getSizeInCell(view, pHeight, cellHeight);
@@ -749,9 +860,14 @@
 
     // Inner classes
 
+    /*
+     This internal class houses the algorithm for computing the locations of grid lines;
+     along either the horizontal or vertical axis. A GridLayout uses two instances of this class -
+     distinguished by the "horizontal" flag which is true for the horizontal axis and false
+     for the vertical one.
+     */
     private class Axis {
         private static final int MIN_VALUE = -1000000;
-        private static final int MAX_VALUE = 1000000;
 
         private static final int UNVISITED = 0;
         private static final int PENDING = 1;
@@ -766,20 +882,25 @@
         PackedMap<Group, Bounds> groupBounds;
         public boolean groupBoundsValid = false;
 
-        PackedMap<Interval, Int> spanSizes;
+        PackedMap<Interval, MutableInt> spanSizes;
         public boolean spanSizesValid = false;
 
-        public int[] locations;
-
         public int[] leadingMargins;
+        public boolean leadingMarginsValid = false;
+
         public int[] trailingMargins;
+        public boolean trailingMarginsValid = false;
 
         public Arc[] arcs;
         public boolean arcsValid = false;
 
-        private boolean mOrderPreserved = DEFAULT_ORDER_PRESERVED;
+        public int[] minima;
+        public boolean minimaValid = false;
 
-        public int prefSizeOfWeightedComponent;
+        public float[] weights;
+        public int[] locations;
+
+        private boolean mOrderPreserved = DEFAULT_ORDER_PRESERVED;
 
         private Axis(boolean horizontal) {
             this.horizontal = horizontal;
@@ -844,17 +965,17 @@
             for (int i = 0; i < groupBounds.values.length; i++) {
                 groupBounds.values[i].reset();
             }
-            for (int i = 0, size = getChildCount(); i < size; i++) {
+            for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
                 LayoutParams lp = getLayoutParams(c);
                 Group g = horizontal ? lp.columnGroup : lp.rowGroup;
 
                 Bounds bounds = groupBounds.getValue(i);
-                int dim = getMeasurement(c, horizontal, PRF);
+
+                int size = getMeasurementIncludingMargin(c, horizontal, PRF);
                 // todo test this works correctly when the returned value is UNDEFINED
-                int below = g.alignment.getAlignmentValue(c, dim);
-                int above = dim - below;
-                bounds.include(-below, above);
+                int below = getAlignmentValue(g.alignment, c, size, horizontal, c);
+                bounds.include(-below, size - below);
             }
         }
 
@@ -870,36 +991,36 @@
         }
 
         // Add values computed by alignment - taking the max of all alignments in each span
-        private PackedMap<Interval, Int> createSpanSizes() {
+        private PackedMap<Interval, MutableInt> createSpanSizes() {
             PackedMap<Group, Bounds> groupBounds = getGroupBounds();
             int N = groupBounds.keys.length;
             Interval[] spans = new Interval[N];
-            Int[] values = new Int[N];
+            MutableInt[] values = new MutableInt[N];
             for (int i = 0; i < N; i++) {
                 Interval key = groupBounds.keys[i].span;
 
                 spans[i] = key;
-                values[i] = new Int();
+                values[i] = new MutableInt();
             }
-            return new PackedMap<Interval, Int>(spans, values);
+            return new PackedMap<Interval, MutableInt>(spans, values);
         }
 
         private void computeSpanSizes() {
-            Int[] spans = spanSizes.values;
+            MutableInt[] spans = spanSizes.values;
             for (int i = 0; i < spans.length; i++) {
                 spans[i].reset();
             }
 
-            Bounds[] bounds = getGroupBounds().values;  // us get to trigger a re-evaluation
+            Bounds[] bounds = getGroupBounds().values;  // use getter to trigger a re-evaluation
             for (int i = 0; i < bounds.length; i++) {
                 int value = bounds[i].size();
 
-                Int valueHolder = spanSizes.getValue(i);
+                MutableInt valueHolder = spanSizes.getValue(i);
                 valueHolder.value = max(valueHolder.value, value);
             }
         }
 
-        private PackedMap<Interval, Int> getSpanSizes() {
+        private PackedMap<Interval, MutableInt> getSpanSizes() {
             if (spanSizes == null) {
                 spanSizes = createSpanSizes();
             }
@@ -910,9 +1031,7 @@
             return spanSizes;
         }
 
-        private void include(List<Arc> arcs, Interval key, Int size, boolean maximizing) {
-            key = maximizing ? key.inverse() : key;
-            size = maximizing ? size.neg() : size;
+        private void include(List<Arc> arcs, Interval key, MutableInt size) {
             // this bit below should really be computed outside here -
             // its just to stop default (col>0) constraints obliterating valid entries
             for (Arc arc : arcs) {
@@ -924,22 +1043,22 @@
             arcs.add(new Arc(key, size));
         }
 
-        private void include2(List<Arc> arcs, Interval span, Int min, Int max,
-                boolean both, boolean maximizing) {
-            include(arcs, span, min, maximizing);
+        private void include2(List<Arc> arcs, Interval span, MutableInt min, MutableInt max,
+                boolean both) {
+            include(arcs, span, min);
             if (both) {
-                include(arcs, span.inverse(), max.neg(), maximizing);
+                // todo
+//                include(arcs, span.inverse(), max.neg());
             }
         }
 
-        private void include2(List<Arc> arcs, Interval span, int min, int max,
-                boolean both, boolean maximizing) {
-            include2(arcs, span, new Int(min), new Int(max), both, maximizing);
+        private void include2(List<Arc> arcs, Interval span, int min, int max, boolean both) {
+            include2(arcs, span, new MutableInt(min), new MutableInt(max), both);
         }
 
-        // Group arcs by their first index, returning an array of arrays.
+        // Group arcs by their first vertex, returning an array of arrays.
         // This is linear in the number of arcs.
-        private Arc[][] index(Arc[] arcs) {
+        private Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
             int N = getCount() + 1;// the number of vertices
             Arc[][] result = new Arc[N][];
             int[] sizes = new int[N];
@@ -959,18 +1078,21 @@
             return result;
         }
 
-        // todo do we always add first element?
-        private Arc[] sort(final Arc[] arcs, int start) {
+        /*
+        Topological sort.
+         */
+        private Arc[] topologicalSort(final Arc[] arcs, int start) {
+        // todo ensure the <start> vertex is added in edge cases
             final List<Arc> result = new ArrayList<Arc>();
             new Object() {
-                Arc[][] index = index(arcs);
+                Arc[][] arcsByFirstVertex = groupArcsByFirstVertex(arcs);
                 int[] visited = new int[getCount() + 1];
 
                 boolean completesCycle(int loc) {
                     int state = visited[loc];
                     if (state == UNVISITED) {
                         visited[loc] = PENDING;
-                        for (Arc arc : index[loc]) {
+                        for (Arc arc : arcsByFirstVertex[loc]) {
                             Interval span = arc.span;
                             // the recursive call
                             if (completesCycle(span.max)) {
@@ -1006,7 +1128,7 @@
             return result;
         }
 
-        // todo unify with findUsed above
+        // todo unify with findUsed above. Both routines analyze which rows/columns are empty.
         private Collection<Interval> getSpacers() {
             List<Interval> result = new ArrayList<Interval>();
             int N = getCount() + 1;
@@ -1038,16 +1160,16 @@
             return result;
         }
 
-        private Arc[] createArcs(boolean maximizing) {
+        private Arc[] createArcs() {
             List<Arc> spanToSize = new ArrayList<Arc>();
 
             // Add all the preferred elements that were not defined by the user.
-            PackedMap<Interval, Int> spanSizes = getSpanSizes();
+            PackedMap<Interval, MutableInt> spanSizes = getSpanSizes();
             for (int i = 0; i < spanSizes.keys.length; i++) {
                 Interval key = spanSizes.keys[i];
-                Int value = spanSizes.values[i];
+                MutableInt value = spanSizes.values[i];
                 // todo remove value duplicate
-                include2(spanToSize, key, value, value, accommodateBothMinAndMax, maximizing);
+                include2(spanToSize, key, value, value, accommodateBothMinAndMax);
             }
 
             // Find redundant rows/cols and glue them together with 0-length arcs to link the tree
@@ -1055,8 +1177,8 @@
             for (int i = 0; i < getCount(); i++) {
                 if (!used[i]) {
                     Interval span = new Interval(i, i + 1);
-                    include(spanToSize, span, new Int(0), maximizing);
-                    include(spanToSize, span.inverse(), new Int(0), maximizing);
+                    include(spanToSize, span, new MutableInt(0));
+                    include(spanToSize, span.inverse(), new MutableInt(0));
                 }
             }
 
@@ -1064,21 +1186,21 @@
                 // Add preferred gaps
                 for (int i = 0; i < getCount(); i++) {
                     if (used[i]) {
-                        include2(spanToSize, new Interval(i, i + 1), 0, 0, false, maximizing);
+                        include2(spanToSize, new Interval(i, i + 1), 0, 0, false);
                     }
                 }
             } else {
                 for (Interval gap : getSpacers()) {
-                    include2(spanToSize, gap, 0, 0, false, maximizing);
+                    include2(spanToSize, gap, 0, 0, false);
                 }
             }
             Arc[] arcs = spanToSize.toArray(new Arc[spanToSize.size()]);
-            return sort(arcs, maximizing ? getCount() : 0);
+            return topologicalSort(arcs, 0);
         }
 
-        public Arc[] getArcs(boolean maximizing) {
+        public Arc[] getArcs() {
             if (arcs == null) {
-                arcs = createArcs(maximizing);
+                arcs = createArcs();
             }
             if (!arcsValid) {
                 getSpanSizes();
@@ -1087,21 +1209,54 @@
             return arcs;
         }
 
-        private boolean relax(int[] locations, Arc entry, boolean maximizing) {
+        private boolean relax(int[] locations, Arc entry) {
             Interval span = entry.span;
             int u = span.min;
             int v = span.max;
             int value = entry.value.value;
             int candidate = locations[u] + value;
-            if (maximizing ? candidate < locations[v] : candidate > locations[v]) {
+            if (candidate > locations[v]) {
                 locations[v] = candidate;
                 return true;
             }
             return false;
         }
 
-        // Bellman-Ford variant
-        private int[] solve(Arc[] arcs, int[] locations, boolean maximizing) {
+        /*
+        Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N)
+
+        GridLayout converts its requirements into a system of linear constraints of the
+        form:
+
+        x[i] - x[j] < a[k]
+
+        Where the x[i] are variables and the a[k] are constants.
+
+        For example, if the variables were instead labeled x, y, z we might have:
+
+            x - y < 17
+            y - z < 23
+            z - x < 42
+
+        This is a special case of the Linear Programming problem that is, in turn,
+        equivalent to the single-source shortest paths problem on a digraph, for
+        which the O(n^2) Bellman-Ford algorithm the most commonly used general solution.
+
+        Other algorithms are faster in the case where no arcs have negative weights
+        but allowing negative weights turns out to be the same as accommodating maximum
+        size requirements as well as minimum ones.
+
+        Bellman-Ford works by iteratively 'relaxing' constraints over all nodes (an O(N)
+        process) and performing this step N times. Proof of correctness hinges on the
+        fact that there can be no negative weight chains of length > N - unless a
+        'negative weight loop' exists. The algorithm catches this case in a final
+        checking phase that reports failure.
+
+        By topologically sorting the nodes and checking this condition at each step
+        typical layout problems complete after the first iteration and the algorithm
+        completes in O(N) steps with very low constants.
+        */
+        private int[] solve(Arc[] arcs, int[] locations) {
             int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
 
             boolean changed = false;
@@ -1109,11 +1264,11 @@
             for (int i = 0; i < N; i++) {
                 changed = false;
                 for (int j = 0, length = arcs.length; j < length; j++) {
-                    changed = changed | relax(locations, arcs[j], maximizing);
+                    changed = changed | relax(locations, arcs[j]);
                 }
                 if (!changed) {
                     if (DEBUG) {
-                        Log.d(TAG, "Iteration " + (maximizing ? "(max)" : "(min)") +
+                        Log.d(TAG, "Iteration " +
                                 " completed after " + (1 + i) + " steps out of " + N);
                     }
                     break;
@@ -1125,119 +1280,158 @@
             return locations;
         }
 
-        private int[] init(int defaultValue, int min, int max) {
-            int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
-            int[] locations = new int[N];
-            Arrays.fill(locations, defaultValue);
-            locations[0] = min;
-            locations[N - 1] = max;
-            return locations;
-        }
-
-        private int[] computeMargins(boolean leading) {
-            int[] result = new int[getCount() + 1];
+        private void computeMargins(boolean leading) {
+            int[] margins = leading ? leadingMargins : trailingMargins;
             for (int i = 0, size = getChildCount(); i < size; i++) {
                 View c = getChildAt(i);
                 LayoutParams lp = getLayoutParams(c);
                 Group g = horizontal ? lp.columnGroup : lp.rowGroup;
                 Interval span = g.span;
                 int index = leading ? span.min : span.max;
-                result[index] = max(result[index], getMargin(c, leading, horizontal));
+                margins[index] = max(margins[index], getMargin(c, leading, horizontal));
             }
-            return result;
         }
 
-        // has side effects
-        private void computeLocations(int[] locations, boolean maximizing) {
-            leadingMargins = computeMargins(true);
-            trailingMargins = computeMargins(false);
+        private int[] getLeadingMargins() {
+            if (leadingMargins == null) {
+                leadingMargins = new int[getCount() + 1];
+            }
+            if (!leadingMarginsValid) {
+                computeMargins(true);
+                leadingMarginsValid = true;
+            }
+            return leadingMargins;
+        }
 
-            solve(getArcs(maximizing), locations, maximizing);
+        private int[] getTrailingMargins() {
+            if (trailingMargins == null) {
+                trailingMargins = new int[getCount() + 1];
+            }
+            if (!trailingMarginsValid) {
+                computeMargins(false);
+                trailingMarginsValid = true;
+            }
+            return trailingMargins;
+        }
 
-            // Add margins
+        private void addMargins() {
+            int[] leadingMargins = getLeadingMargins();
+            int[] trailingMargins = getTrailingMargins();
+
             int delta = 0;
-            for (int i = 0; i < getCount(); i++) {
+            for (int i = 0, N = getCount(); i < N; i++) {
                 int margins = leadingMargins[i] + trailingMargins[i + 1];
                 delta += margins;
-                locations[i + 1] += delta;
+                minima[i + 1] += delta;
             }
         }
 
+        private int getLocationIncludingMargin(View view, boolean leading, int index) {
+            int location = locations[index];
+            int margin;
+            if (!mMarginsIncludedInAlignment) {
+                margin = (leading ? leadingMargins : trailingMargins)[index];
+            } else {
+                margin = getMargin(view, leading, horizontal);
+            }
+            return leading ? (location + margin) : (location - margin);
+        }
+
+        private void computeMinima(int[] a) {
+            Arrays.fill(a, MIN_VALUE);
+            a[0] = 0;
+            solve(getArcs(), a);
+            if (!mMarginsIncludedInAlignment) {
+                addMargins();
+            }
+        }
+
+        private int[] getMinima() {
+            if (minima == null) {
+                int N = getCount() + 1;
+                minima = new int[N];
+            }
+            if (!minimaValid) {
+                computeMinima(minima);
+                minimaValid = true;
+            }
+            return minima;
+        }
+
+        private void computeWeights() {
+            for (int i = 0, N = getChildCount(); i < N; i++) {
+                LayoutParams lp = getLayoutParams(getChildAt(i));
+                Group g = horizontal ? lp.columnGroup : lp.rowGroup;
+                Interval span = g.span;
+                int penultimateIndex = span.max - 1;
+                weights[penultimateIndex] += horizontal ? lp.columnWeight : lp.rowWeight;
+            }
+        }
+
+        private float[] getWeights() {
+            if (weights == null) {
+                int N = getCount() + 1;
+                weights = new float[N];
+            }
+            computeWeights();
+            return weights;
+        }
+
+        private int[] getLocations() {
+            if (locations == null) {
+                int N = getCount() + 1;
+                locations = new int[N];
+            }
+            return locations;
+        }
+
+        // External entry points
+
         private int size(int[] locations) {
             return locations[locations.length - 1] - locations[0];
         }
 
-        private int[] getLimit(boolean lowerBound, boolean maximizing) {
-            int defaultValue = maximizing ? MAX_VALUE : MIN_VALUE;
-            if (lowerBound) {
-                // as long as it avoids overflow, the upper bound can be anything (including zero)
-                int[] result = init(defaultValue, defaultValue, 1000);
-                computeLocations(result, maximizing);
-                int delta = result[0];
-                for (int i = 0; i < result.length; i++) {
-                    result[i] -= delta;
-                }
-                return result;
-            } else {
-                int[] result = init(defaultValue, 0, defaultValue);
-                computeLocations(result, maximizing);
-                return result;
-            }
-        }
-
-        // External entry points
-
         private int getMin() {
-            int[] mins = getLimit(maximizing, maximizing);
-            return size(mins);
-        }
-
-        private int getPref() {
-            return accommodateBothMinAndMax ? getMax() : getMin();
-        }
-
-        private int getMax() {
-            int[] maxs = getLimit(!maximizing, maximizing);
-            return size(maxs);
-        }
-
-        private int totalMarginSize() {
-            return sum(leadingMargins) + sum(trailingMargins);
+            return size(getMinima());
         }
 
         private void layout(int targetSize) {
-            int N = getCount() + 1;
-            int min = getMin();
-            int max = getMax();
+            int[] mins = getMinima();
 
-            int clippedTargetSize = max(min(max, targetSize), min); // confine size to valid range
+            int totalDelta = max(0, targetSize - size(mins)); // confine to expansion
 
-            if (DEBUG) {
-                Log.d(TAG, "Computing sizes for target " + clippedTargetSize + " for " +
-                        (horizontal ? "col" : "row") + "s from: " + arcs);
+            float[] weights = getWeights();
+            float totalWeight = sum(weights);
+
+            if (totalWeight == 0f) {
+                weights[weights.length - 1] = 1;
+                totalWeight = 1;
             }
-            int delta = clippedTargetSize - min;
-            prefSizeOfWeightedComponent = delta;
-            invalidateValues();
-            int defaultValue = maximizing ? MAX_VALUE : MIN_VALUE;
-            locations = init(defaultValue, 0, clippedTargetSize - totalMarginSize());
-            computeLocations(locations, maximizing);
-            prefSizeOfWeightedComponent = 0;
 
-            if (DEBUG) {
-                Log.d(TAG, "locations = " + Arrays.toString(locations));
-                int[] computedSizes = new int[N - 1];
-                for (int i = 0; i < N - 1; i++) {
-                    computedSizes[i] = locations[i + 1] - locations[i];
-                }
-                Log.d(TAG, "sizes = " + Arrays.toString(computedSizes));
+            int[] locations = getLocations();
+            int cumulativeDelta = 0;
+
+            for (int i = 0; i < locations.length; i++) {
+                float weight = weights[i];
+                int delta = (int) (totalDelta * weight / totalWeight);
+                cumulativeDelta += delta;
+                locations[i] = mins[i] + cumulativeDelta;
+
+                totalDelta -= delta;
+                totalWeight -= weight;
             }
         }
 
         private void invalidateStructure() {
             countValid = false;
+
             groupBounds = null;
             spanSizes = null;
+            leadingMargins = null;
+            trailingMargins = null;
+            minima = null;
+            weights = null;
+            locations = null;
 
             invalidateValues();
         }
@@ -1246,6 +1440,9 @@
             groupBoundsValid = false;
             spanSizesValid = false;
             arcsValid = false;
+            leadingMarginsValid = false;
+            trailingMarginsValid = false;
+            minimaValid = false;
         }
     }
 
@@ -1259,8 +1456,8 @@
      * {@link Group Groups} are immutable structures and may be shared between the layout
      * parameters of different children.
      * <p>
-     * The {@link Group#span span} fields of the row and column groups together specify
-     * the four grid indices that delimit the cells of this cell group.
+     * The row and column groups contain the leading and trailing indices along each axis
+     * and together specify the four grid indices that delimit the cells of this cell group.
      * <p>
      * The {@link Group#alignment alignment} fields of the row and column groups together specify
      * both aspects of alignment within the cell group. It is also possible to specify a child's
@@ -1277,19 +1474,19 @@
      *     <li>{@link #height} = {@link #WRAP_CONTENT}</li>
      *     <li>{@link #topMargin} = 0 when
      *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
-     *          <code>false</code>; otherwise {@link Integer#MIN_VALUE}, to
+     *          <code>false</code>; otherwise {@link #UNDEFINED}, to
      *          indicate that a default value should be computed on demand. </li>
      *     <li>{@link #leftMargin} = 0 when
      *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
-     *          <code>false</code>; otherwise {@link Integer#MIN_VALUE}, to
+     *          <code>false</code>; otherwise {@link #UNDEFINED}, to
      *          indicate that a default value should be computed on demand. </li>
      *     <li>{@link #bottomMargin} = 0 when
      *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
-     *          <code>false</code>; otherwise {@link Integer#MIN_VALUE}, to
+     *          <code>false</code>; otherwise {@link #UNDEFINED}, to
      *          indicate that a default value should be computed on demand. </li>
      *     <li>{@link #rightMargin} = 0 when
      *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
-     *          <code>false</code>; otherwise {@link Integer#MIN_VALUE}, to
+     *          <code>false</code>; otherwise {@link #UNDEFINED}, to
      *          indicate that a default value should be computed on demand. </li>
      *     <li>{@link #rowGroup}<code>.span</code> = <code>[0, 1]</code> </li>
      *     <li>{@link #rowGroup}<code>.alignment</code> = {@link #BASELINE} </li>
@@ -1324,7 +1521,8 @@
                 new Group(DEFAULT_SPAN, DEFAULT_HORIZONTAL_ALIGNMENT);
         private static final Group DEFAULT_VERTICAL_GROUP =
                 new Group(DEFAULT_SPAN, DEFAULT_VERTCIAL_ALGIGNMENT);
-        private static final int DEFAULT_WEIGHT = 0;
+        private static final int DEFAULT_WEIGHT_0 = 0;
+        private static final int DEFAULT_WEIGHT_1 = 1;
 
         // Misc
 
@@ -1397,7 +1595,7 @@
         public LayoutParams(Group rowGroup, Group columnGroup) {
             this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
                     DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
-                    rowGroup, columnGroup, DEFAULT_WEIGHT, DEFAULT_WEIGHT);
+                    rowGroup, columnGroup, DEFAULT_WEIGHT_0, DEFAULT_WEIGHT_0);
         }
 
         /**
@@ -1515,22 +1713,26 @@
                     !definesVertical(gravity), defaultAlignment);
         }
 
+        private int getDefaultWeight(int size) {
+            return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0;
+        }
+
         private void init(Context context, AttributeSet attrs, int defaultGravity) {
             TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
             try {
                 int gravity = a.getInteger(GRAVITY, defaultGravity);
 
                 int column = a.getInteger(COLUMN, DEFAULT_COLUMN);
-                int width = a.getInteger(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
-                Interval colSpan = new Interval(column, column + width);
-                this.columnGroup = new Group(colSpan, getHorizontalAlignment(gravity, width));
-                this.columnWeight = a.getFloat(COLUMN_WEIGHT, DEFAULT_WEIGHT);
+                int columnSpan = a.getInteger(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
+                Interval hSpan = new Interval(column, column + columnSpan);
+                this.columnGroup = new Group(hSpan, getHorizontalAlignment(gravity, width));
+                this.columnWeight = a.getFloat(COLUMN_WEIGHT, getDefaultWeight(width));
 
                 int row = a.getInteger(ROW, DEFAULT_ROW);
-                int height = a.getInteger(ROW_SPAN, DEFAULT_SPAN_SIZE);
-                Interval rowSpan = new Interval(row, row + height);
-                this.rowGroup = new Group(rowSpan, getVerticalAlignment(gravity, height));
-                this.rowWeight = a.getFloat(ROW_WEIGHT, DEFAULT_WEIGHT);
+                int rowSpan = a.getInteger(ROW_SPAN, DEFAULT_SPAN_SIZE);
+                Interval vSpan = new Interval(row, row + rowSpan);
+                this.rowGroup = new Group(vSpan, getVerticalAlignment(gravity, height));
+                this.rowWeight = a.getFloat(ROW_WEIGHT, getDefaultWeight(height));
             } finally {
                 a.recycle();
             }
@@ -1563,12 +1765,16 @@
         }
     }
 
+    /*
+    In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs.
+    Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles.
+     */
     private static class Arc {
         public final Interval span;
-        public final Int value;
+        public final MutableInt value;
         public boolean completesCycle;
 
-        public Arc(Interval span, Int value) {
+        public Arc(Interval span, MutableInt value) {
             this.span = span;
             this.value = value;
         }
@@ -1581,27 +1787,36 @@
 
     // A mutable Integer - used to avoid heap allocation during the layout operation
 
-    private static class Int {
+    private static class MutableInt {
         public int value;
 
-        private Int() {
+        private MutableInt() {
             reset();
         }
 
-        private Int(int value) {
+        private MutableInt(int value) {
             this.value = value;
         }
 
         private void reset() {
             value = Integer.MIN_VALUE;
         }
-
-        private Int neg() {
-            // this should never be called
-            throw new UnsupportedOperationException();
-        }
     }
 
+    /*
+    This data structure is used in place of a Map where we have an index that refers to the order
+    in which each key/value pairs were added to the map. In this case we store keys and values
+    in arrays of a length that is equal to the number of unique keys. We also maintain an
+    array of indexes from insertion order to the compacted arrays of keys and values.
+
+    Note that behavior differs from that of a LinkedHashMap in that repeated entries
+    *do* get added multiples times. So the length of index is equals to the number of
+    items added.
+
+    This is useful in the GridLayout class where we can rely on the order of children not
+    changing during layout - to use integer-based lookup for our internal structures
+    rather than using (and storing) an implementation of Map<Key, ?>.
+     */
     @SuppressWarnings(value = "unchecked")
     private static class PackedMap<K, V> {
         public final int[] index;
@@ -1611,8 +1826,8 @@
         private PackedMap(K[] keys, V[] values) {
             this.index = createIndex(keys);
 
-            this.keys = index(keys, index);
-            this.values = index(values, index);
+            this.keys = compact(keys, index);
+            this.values = compact(values, index);
         }
 
         private K getKey(int i) {
@@ -1648,19 +1863,33 @@
             return result;
         }
 
-        private static <K> K[] index(K[] keys, int[] index) {
-            int size = keys.length;
-            Class<?> componentType = keys.getClass().getComponentType();
+        /*
+        Create a compact array of keys or values using the supplied index.
+         */
+        private static <K> K[] compact(K[] a, int[] index) {
+            int size = a.length;
+            Class<?> componentType = a.getClass().getComponentType();
             K[] result = (K[]) Array.newInstance(componentType, max(index, -1) + 1);
 
             // this overwrite duplicates, retaining the last equivalent entry
             for (int i = 0; i < size; i++) {
-                result[index[i]] = keys[i];
+                result[index[i]] = a[i];
             }
             return result;
         }
     }
 
+    /*
+    For each Group (with a given alignment) we need to store the amount of space required
+    above the alignment point and the amount of space required below it. One side of this
+    calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
+    For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
+    simple optimisations are possible.
+
+    The general algorithm therefore is to create a Map (actually a PackedMap) from
+    Group to Bounds and to loop through all Views in the group taking the maximum
+    of the values for each View.
+    */
     private static class Bounds {
         public int below;
         public int above;
@@ -1708,11 +1937,12 @@
      * Intervals are often written as <code>[min, max]</code> and represent the set of values
      * <em>x</em> such that <em>min <= x < max</em>.
      */
-    public static class Interval {
+    /* package */ static class Interval {
         /**
          * The minimum value.
          */
         public final int min;
+
         /**
          * The maximum value.
          */
@@ -1793,14 +2023,13 @@
      */
     public static class Group {
         /**
-         * The {@link Interval#min min} and {@link Interval#max max} values of
-         * a span specify the grid indices of the leading and trailing edges of
-         * the cell group.
+         * The grid indices of the leading and trailing edges of this cell group for the
+         * appropriate axis.
          * <p>
          * See {@link GridLayout} for a description of the conventions used by GridLayout
          * for grid indices.
          */
-        public final Interval span;
+        /* package */ final Interval span;
         /**
          * Specifies how cells should be aligned in this group.
          * For row groups, this specifies the vertical alignment.
@@ -1818,7 +2047,7 @@
          * @param span      the span.
          * @param alignment the alignment.
          */
-        public Group(Interval span, Alignment alignment) {
+        /* package */ Group(Interval span, Alignment alignment) {
             this.span = span;
             this.alignment = alignment;
         }
@@ -1861,7 +2090,7 @@
         }
 
         /**
-         * Returns true if the {@link #getClass class}, {@link #alignment} and {@link #span}
+         * Returns true if the {@link #getClass class}, {@link #alignment} and <code>span</code>
          * properties of this Group and the supplied parameter are pairwise equal; false otherwise.
          *
          * @param that the object to compare this group with.
@@ -1898,9 +2127,6 @@
         }
     }
 
-    // Alignments
-
-
     /**
      * Alignments specify where a view should be placed within a cell group and
      * what size it should be.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9592d0c..35e78fb 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9318,7 +9318,6 @@
         private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds
 
         // Used to detect taps on the insertion handle, which will affect the PastePopupWindow
-        private long mTouchTimer;
         private float mDownPositionX, mDownPositionY;
         private PastePopupWindow mPastePopupWindow;
         private Runnable mHider;
@@ -9392,22 +9391,18 @@
                 case MotionEvent.ACTION_DOWN:
                     mDownPositionX = ev.getRawX();
                     mDownPositionY = ev.getRawY();
-                    mTouchTimer = SystemClock.uptimeMillis();
                     break;
 
                 case MotionEvent.ACTION_UP:
-                    long delay = SystemClock.uptimeMillis() - mTouchTimer;
-                    if (delay < ViewConfiguration.getTapTimeout()) {
-                        final float deltaX = mDownPositionX - ev.getRawX();
-                        final float deltaY = mDownPositionY - ev.getRawY();
-                        final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
-                        if (distanceSquared < mSquaredTouchSlopDistance) {
-                            if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
-                                // Tapping on the handle dismisses the displayed paste view,
-                                mPastePopupWindow.hide();
-                            } else {
-                                show(0);
-                            }
+                    final float deltaX = mDownPositionX - ev.getRawX();
+                    final float deltaY = mDownPositionY - ev.getRawY();
+                    final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+                    if (distanceSquared < mSquaredTouchSlopDistance) {
+                        if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
+                            // Tapping on the handle dismisses the displayed paste view,
+                            mPastePopupWindow.hide();
+                        } else {
+                            show(0);
                         }
                     }
                     hideDelayed();
@@ -10010,7 +10005,7 @@
 
     private boolean                 mSelectAllOnFocus = false;
 
-    private int                     mGravity = Gravity.TOP | Gravity.LEFT;
+    private int                     mGravity = Gravity.TOP | Gravity.BEFORE;
     private boolean                 mHorizontallyScrolling;
 
     private int                     mAutoLinkMask;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 419578c..110268e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1098,6 +1098,13 @@
         android:description="@string/permdesc_setOrientation"
         android:protectionLevel="signature" />
 
+    <!-- Allows low-level access to setting the pointer speed.
+         Not for use by normal applications. -->
+    <permission android:name="android.permission.SET_POINTER_SPEED"
+        android:label="@string/permlab_setPointerSpeed"
+        android:description="@string/permdesc_setPointerSpeed"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to install packages. -->
     <permission android:name="android.permission.INSTALL_PACKAGES"
         android:label="@string/permlab_installPackages"
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index 08b163a..9769bbb7 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
index 7f830bc..9769bbb7 100644
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 8603e93..06cfc70 100755
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
index 911f86d..06cfc70 100755
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
index 9c0ff47..f7debee 100644
--- a/core/res/res/drawable-xhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
new file mode 100644
index 0000000..f7debee
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml
index bdbbfcb..3f99dde 100755
--- a/core/res/res/layout/app_perms_summary.xml
+++ b/core/res/res/layout/app_perms_summary.xml
@@ -60,10 +60,11 @@
             android:orientation="horizontal"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="16dip"
-            android:layout_marginBottom="12dip"
-            android:layout_marginLeft="16dip"
-            android:duplicateParentState="true">
+            android:paddingTop="16dip"
+            android:paddingBottom="12dip"
+            android:paddingLeft="16dip"
+            android:duplicateParentState="true"
+            android:background="?android:attr/selectableItemBackground">
 
             <TextView
                 android:id="@+id/show_more_text"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 764ec85..38b62d4 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1235,6 +1235,12 @@
     <skip />
     <!-- no translation found for launch_warning_original (188102023021668683) -->
     <skip />
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <!-- no translation found for smv_application (295583804361236288) -->
     <skip />
     <!-- no translation found for smv_process (5120397012047462446) -->
@@ -1540,4 +1546,6 @@
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9b677c2..9c22f0e 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1154,6 +1154,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"ትግበራ ተዘዋውሯል"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> እየሄደ ነው።"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> በዋናነት የተነሳው።"</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"ትግበራው <xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g> ሂደት) በራስ ተነሳሺ StrictMode ፖሊሲን ይተላለፋል።"</string>
     <string name="smv_process" msgid="5120397012047462446">"ሂደቱ <xliff:g id="PROCESS">%1$s</xliff:g> በራስ ተነሳሺ StrictMode ፖሊሲን ይተላለፋል።"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string>
@@ -1423,4 +1429,6 @@
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6795348..c9454d3 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"تمت إعادة توجيه التطبيق"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل الآن."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"تم تشغيل <xliff:g id="APP_NAME">%1$s</xliff:g> من الأصل."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة.StrictMode المفروضة ذاتيًا."</string>
     <string name="smv_process" msgid="5120397012047462446">"انتهكت العملية <xliff:g id="PROCESS">%1$s</xliff:g> سياسة StrictMode المفروضة ذاتيًا."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> يعمل"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"وحدة التخزين الداخلية"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"بطاقة SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"وحدة تخزين USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4710226..70eb79a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Приложението се пренасочи"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Първоначално бе стартирано: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Приложението <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) наруши правилото за стриктен режим, наложено от самото него."</string>
     <string name="smv_process" msgid="5120397012047462446">"Процесът <xliff:g id="PROCESS">%1$s</xliff:g> наруши правилото за стриктен режим, наложено от самия него."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> се изпълнява"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Вътрешно хранилище"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD карта"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e2aec56..45201c1 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplicació redirigida"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va iniciar originalment."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> (procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
     <string name="smv_process" msgid="5120397012047462446">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> ha incomplert la seva política de mode estricte."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Emmagatzematge intern"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Targeta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7f92410..f88e381 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplikace přesměrována"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Je spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Původně byla spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil své vlastní vynucené zásady StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Interní úložiště"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Karta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 7b05a0e..c6946d4 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Programmet er omdirigeret"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører nu."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> blev oprindeligt åbnet."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
     <string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Internt lager"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-kort"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 38c8f6c..ffef226 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Anwendung umgeleitet"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird jetzt ausgeführt."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> wurde ursprünglich gestartet."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen ihre selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
     <string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Interner Speicher"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-Karte"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 017be9b..bf1d432f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Ανακατεύθυνση εφαρμογής"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται τώρα."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Έγινε εκκίνηση πρώτα της εφαρμογής <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλόμενη πολιτική StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Η διεργασία <xliff:g id="PROCESS">%1$s</xliff:g> παραβίασε την αυτοεπιβαλόμενη πολιτική StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Εσωτερικός χώρος αποθήκευσης"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Κάρτα SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Χώρος αποθήκευσης USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index abf18f1..b0e77ba 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Application redirected"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is now running."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was originally launched."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced StrictMode policy."</string>
     <string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Internal Storage"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD Card"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 178e076..fb97c4a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Se redirigió la aplicación"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando ahora."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha violado su política StrictMode autoimpuesta."</string>
     <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Almacenamiento interno"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Tarjeta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 968a3be..a1e3a54 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -241,7 +241,7 @@
     <string name="permlab_backup" msgid="470013022865453920">"controlar las copias de seguridad y las restauraciones del sistema"</string>
     <string name="permdesc_backup" msgid="4837493065154256525">"Permite que la aplicación controle el mecanismo de copia de seguridad y restauración del sistema. Este permiso no está destinado a aplicaciones normales."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"confirmar restauración o copia de seguridad completa"</string>
-    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Permite que la aplicación inicie la interfaz de usuario de confirmación de copia de seguridad completa (ninguna aplicación debe utilizarla)."</string>
+    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Permite que la aplicación inicie la interfaz de usuario de confirmación de copia de seguridad completa (ninguna aplicación debería utilizarla)."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
     <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas destinadas al uso por parte de la interfaz de usuario interna del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas de nivel del sistema"</string>
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplicación redireccionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Inicialmente, se inició la aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
     <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha infringido su política StrictMode autoaplicable."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Almacenamiento interno"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Tarjeta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index df748cd..00d173d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"برنامه هدایت مجدد شد"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> اکنون در حال اجرا است."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ابتدا راه اندازی شد."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خط مشی StrictMode اجرای خودکار را نقض کرده است."</string>
     <string name="smv_process" msgid="5120397012047462446">"فرآیند <xliff:g id="PROCESS">%1$s</xliff:g> خط مشی StrictMode اجرای خودکار خود را نقض کرده است."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"حافظه داخلی"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"کارت SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"حافظه USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6b06197..2d3bf48 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Sovellus uudelleenohjasi"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nyt käynnissä."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> käynnistettiin alun perin."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
     <string name="smv_process" msgid="5120397012047462446">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> käynnissä"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Sisäinen tallennustila"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-kortti"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7b2f9c0..3f3eb93 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -241,7 +241,7 @@
     <string name="permlab_backup" msgid="470013022865453920">"contrôler la sauvegarde et la restauration du système"</string>
     <string name="permdesc_backup" msgid="4837493065154256525">"Autorise l\'application à contrôler le mécanisme de sauvegarde et de restauration du système. Ne pas utiliser pour les applications standard."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"confirmer une sauvegarde complète ou une restauration"</string>
-    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Permet à l\'application de lancer l\'interface utilisateur de confirmation de la sauvegarde complète. Seules certaines applications peuvent bénéficier de cette permission."</string>
+    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Permet à l\'application de lancer l\'interface de confirmation de sauvegarde complète. Seules certaines applications peuvent bénéficier de cette permission."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
     <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Affichage d\'alertes système"</string>
@@ -492,8 +492,8 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquer le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"Définir exp. mot passe verr."</string>
     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Contrôler la fréquence de modification du mot de passe de verrouillage de l\'écran"</string>
-    <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir cryptage du stockage"</string>
-    <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient cryptées"</string>
+    <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir chiffrement du stockage"</string>
+    <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient chiffrées"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domicile"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Application redirigée"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> est maintenant lancée."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Application lancée initialement : <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
     <string name="smv_process" msgid="5120397012047462446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Mémoire de stockage interne"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Carte SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 9a3eb0e..773a8f3 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -240,7 +240,7 @@
     <string name="permdesc_batteryStats" msgid="5847319823772230560">"Omogućuje izmjenu prikupljene statistike o bateriji. Nije za upotrebu na uobičajenim aplikacijama."</string>
     <string name="permlab_backup" msgid="470013022865453920">"sigurnosna kopija i oporavak nadzornog sustava"</string>
     <string name="permdesc_backup" msgid="4837493065154256525">"Aplikaciji omogućuje nadzor nad mehanizmom stvaranja sigurnosnih kopija i oporavka sustava. Nije za upotrebu na uobičajenim aplikacijama."</string>
-    <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"potvrditi potpunu sigurnosnu kopiju ili vratiti rad"</string>
+    <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"potvrditi postupak izrade sigurnosne kopije ili obnove"</string>
     <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Omogućuje aplikaciji pokretanje korisničkog sučelja za potvrdu potpune sigurnosne kopije. Aplikacije ne bi trebale upotrebljavati tu opciju."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"prikaz neovlaštenih prozora"</string>
     <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Omogućuje stvaranje prozora kojima je namjena da se koriste u korisničkom sučelju internog sustava. Nije za upotrebu na uobičajenim aplikacijama."</string>
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplikacija preusmjerena"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvodi sada."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> pokrenuta je prva."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je svoje vlastito pravilo StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je svoje vlastito pravilo StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Izvodi se <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Unutarnja pohrana"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD kartica"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 18426f4..09dd648 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Alk. átirányítva"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> éppen fut."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> volt eredetileg elindítva."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"<xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
     <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> folyamat megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> fut"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Belső tárhely"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-kártya"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index fdd6735..b2f3af8 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplikasi dialihkan"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Penyimpanan Internal"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Kartu SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7cff9c9..19d317e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -241,7 +241,7 @@
     <string name="permlab_backup" msgid="470013022865453920">"controllo del backup di sistema e ripristino"</string>
     <string name="permdesc_backup" msgid="4837493065154256525">"Consente all\'applicazione di controllare il meccanismo di backup e ripristino del sistema. Da non usare per normali applicazioni."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"conferma di un\'operazione completa di backup o di ripristino"</string>
-    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Consente all\'applicazione di lanciare l\'interfaccia utente di conferma del backup completo. Non utilizzabile da qualsiasi applicazione."</string>
+    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Consente all\'applicazione di lanciare l\'interfaccia utente di conferma del backup completo. Non utilizzare per nessuna applicazione."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualizzazione finestre non autorizzate"</string>
     <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visualizzazione avvisi di sistema"</string>
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Applicazione reindirizzata"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> è ora in esecuzione."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> già avviata."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string>
     <string name="smv_process" msgid="5120397012047462446">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> ha violato la norma StrictMode autoimposta."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Archivio interno"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Scheda SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fd8ae47..4aba678 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"היישום נותב מחדש"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> פועל כעת."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> הופעל במקור."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"היישום <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית."</string>
     <string name="smv_process" msgid="5120397012047462446">"התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הפר את מדיניות StrictMode באכיפה עצמית."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> פועל"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"אחסון פנימי"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"כרטיס SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"אמצעי אחסון מסוג USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 100d681..e078274 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"アプリのリダイレクト"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>が実行中です。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>が最初に起動していました。"</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"アプリケーション<xliff:g id="APPLICATION">%1$s</xliff:g>(プロセス<xliff:g id="PROCESS">%2$s</xliff:g>)でStrictModeポリシー違反がありました。"</string>
     <string name="smv_process" msgid="5120397012047462446">"プロセス<xliff:g id="PROCESS">%1$s</xliff:g>でStrictModeポリシー違反がありました。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>を実行中"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"内部ストレージ"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SDカード"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0d5a41e..4d1778e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"애플리케이션 리디렉션됨"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"원래 <xliff:g id="APP_NAME">%1$s</xliff:g>을(를) 실행했습니다."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"애플리케이션 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string>
     <string name="smv_process" msgid="5120397012047462446">"프로세스(<xliff:g id="PROCESS">%1$s</xliff:g>)가 자체 시행 StrictMode 정책을 위반했습니다."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"내부 저장공간"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD 카드"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e3bdea6..5b7ef8c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Programa nukreipta"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ dabar vykdoma."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ buvo iš pradžių paleista."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string>
     <string name="smv_process" msgid="5120397012047462446">"„<xliff:g id="PROCESS">%1$s</xliff:g>“ procesas pažeidė savo vykdomą „StrictMode“ politiką."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Vykdoma „<xliff:g id="APP">%1$s</xliff:g>“"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Vidinė atmintis"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD kortelė"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index db2b1d3..2aa49ca 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Lietojumpr. ir novirzīta"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> tagad darbojas."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Sākotnēji tika palaista lietojumprogramma <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Lietojumprogramma <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string>
     <string name="smv_process" msgid="5120397012047462446">"Process <xliff:g id="PROCESS">%1$s</xliff:g> ir pārkāpis savu pašieviesto StrictMode politiku."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> darbojas"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Iekšējā atmiņa"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD karte"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 09234bd..e82fc10 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1046,6 +1046,12 @@
     <skip />
     <!-- no translation found for launch_warning_original (188102023021668683) -->
     <skip />
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <!-- no translation found for smv_application (295583804361236288) -->
     <skip />
     <!-- no translation found for smv_process (5120397012047462446) -->
@@ -1351,4 +1357,6 @@
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a6867ac..02a414c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Programmet er omdirigert"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører nå."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ble opprinnelig startet."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string>
     <string name="smv_process" msgid="5120397012047462446">"Prosessen<xliff:g id="PROCESS">%1$s</xliff:g> har brutt de selvpålagte StrictMode-retningslinjene."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Intern lagring"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-kort"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d078081..ad214bf 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"App omgeleid"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
     <string name="smv_process" msgid="5120397012047462446">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Interne opslag"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-kaart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8dd3cc7..ed877bb 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplikacja przekierowana"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> została pierwotnie uruchomiona."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> naruszył wymuszone przez siebie zasady StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Działa <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Pamięć wewnętrzna"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Karta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 9ae74dd..7ba9ad0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplicação redireccionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> está agora a ser executado."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi originalmente iniciado."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
     <string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Armazenamento Interno"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Cartão SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 5e37153..750a751 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplicativo redirecionado"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> não está em execução."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi iniciado."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode imposta automaticamente."</string>
     <string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Armazenamento interno"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Cartão SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 4bf9c3e..ff2eecb 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -899,6 +899,12 @@
     <skip />
     <!-- no translation found for launch_warning_original (188102023021668683) -->
     <skip />
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"L\'applicaziun <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ha violà sia atgna directiva StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Il process <xliff:g id="PROCESS">%1$s</xliff:g> ha violà sia atgna directiva StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> vegn exequida"</string>
@@ -1147,4 +1153,6 @@
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c88f06d..7fb4f73 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplicaţie redirecţionată"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Stocare internă"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Card SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e7d4268..fe5815f 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -449,7 +449,7 @@
     <string name="permlab_nfc" msgid="4423351274757876953">"управлять радиосвязью ближнего действия"</string>
     <string name="permdesc_nfc" msgid="9171401851954407226">"Позволяет приложению обмениваться данными с метками, картами и считывателями через радиосвязь ближнего действия (NFC)."</string>
     <string name="permlab_vpn" msgid="8345800584532175312">"перехватывать и изменять сетевой трафик"</string>
-    <string name="permdesc_vpn" msgid="5617893078989944219">"Позволяет приложению перехватывать и проверять весь сетевой трафик, например, чтобы установить соединение VPN. Вредоносное ПО может отслеживать, перенаправлять или изменять сетевые пакеты без вашего ведома."</string>
+    <string name="permdesc_vpn" msgid="5617893078989944219">"Позволяет приложению перехватывать и проверять весь сетевой трафик, например чтобы установить соединение VPN. Вредоносное ПО может отслеживать, перенаправлять или изменять сетевые пакеты без вашего ведома."</string>
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"отключать блокировку клавиатуры"</string>
     <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Позволяет приложению отключить блокировку клавиатуры и другие функции защиты паролем. Примером допустимого использования этой функции является отключение блокировки клавиатуры при получении входящего вызова и включение блокировки после завершения разговора."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"считывать настройки синхронизации"</string>
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Приложение перенаправлено"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Изначально было запущено приложение <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (процесс <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> нарушил собственную политику StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Приложение <xliff:g id="APP">%1$s</xliff:g> запущено"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Внутренняя память"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-карта"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 311da94..d7d9725 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Aplikácia bola presmerov."</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Je spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Pôvodne bola spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil svoje vlastné vynútené pravidlá StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Spustená aplikácia: <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Interný ukladací priestor"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Karta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 2ba3242..cbb097b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Preusmeritev programa"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Prvotno je bil zagnan program <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Program <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samoizvedljivi pravilnik o strogem načinu."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> krši svoj samoizvedljivi pravilnik o strogem načinu."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> se izvaja"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Notranji pomnilnik"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Kartica SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8d8b73f..93faf2f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Апликација је преусмерена"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је сада покренута."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Првобитно је покренута апликација <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string>
     <string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> је прекршио самонаметнуте StrictMode смернице."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Интерна меморија"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD картица"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b2740a0..c3561d7 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Programmet omdirigerades"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> startades först."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string>
     <string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har brutit mot sin egen StrictMode-policy."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Internt lagringsutrymme"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD-kort"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 041365e..453f74e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1154,6 +1154,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Programu imeelekezwa upya"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>inaendesha sasa."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilizinduliwa mwanzoni."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Shughuli ya <xliff:g id="APPLICATION">%1$s</xliff:g> (programu <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Shughuli ya <xliff:g id="PROCESS">%1$s</xliff:g> imeenda kinyume na kulazimisha sera yake ya StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> inaendelea"</string>
@@ -1423,4 +1429,6 @@
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index f05409c..54b33f4 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"เปลี่ยนเส้นทางแอปพลิเคชัน"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงานอยู่ในขณะนี้"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> เปิดใช้ไว้แล้ว"</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
     <string name="smv_process" msgid="5120397012047462446">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงาน"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"ที่เก็บข้อมูลภายใน"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"การ์ด SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 72d361b..9eeac34 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Ni-redirect application"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Tumatakbo na ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Orihinal na nalunsad ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Ang application na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g> ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Panloob na Storage"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD Card"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8688dd8..7f1d3c3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Uygulama yönlendirildi"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"İlk olarak <xliff:g id="APP_NAME">%1$s</xliff:g> başlatıldı."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
     <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Dahili Depolama"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD Kart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB depolama birimi"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7cd9ce1..00e6333 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Програму переадресовано"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Зараз працює <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Спочатку було запущено <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> порушив свою самозастосовну політику StrictMode."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Працює <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Внутрішня пам’ять"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Картка SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index eb4aee3..45c3ad8 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Ứng dụng đã được chuyển hướng"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
     <string name="smv_process" msgid="5120397012047462446">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> đang hoạt động"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"Bộ nhớ trong"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"Thẻ SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 134845a..f5ee751 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"应用程序已重定向"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前正在运行。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>已启动。"</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"应用程序<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
     <string name="smv_process" msgid="5120397012047462446">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>正在运行"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"内存空间"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD 卡"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 存储器"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 7075677..1779baf 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -241,7 +241,7 @@
     <string name="permlab_backup" msgid="470013022865453920">"控制系統備份與還原"</string>
     <string name="permdesc_backup" msgid="4837493065154256525">"允許應用程式控制系統的備份與還原機制。一般應用程式不應使用這項功能。"</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"確認完整備份或還原作業"</string>
-    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"允許應用程式啟動完整備份確認使用者界面,任何應用程式均不應使用這項功能。"</string>
+    <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"允許應用程式啟動完整備份確認使用者介面,任何應用程式均不應使用這項功能。"</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"顯示未授權視窗"</string>
     <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"允許內部系統使用介面建立視窗。一般應用程式不會使用此功能。"</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"顯示系統警示"</string>
@@ -836,6 +836,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"應用程式已重新導向"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在正在執行。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」原先已啟動。"</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
     <string name="smv_process" msgid="5120397012047462446">"處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 執行中"</string>
@@ -1041,4 +1047,6 @@
     <string name="storage_internal" msgid="7556050805474115618">"內部儲存空間"</string>
     <string name="storage_sd_card" msgid="8921771478629812343">"SD 卡"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9fda350..ad143a7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1154,6 +1154,12 @@
     <string name="launch_warning_title" msgid="8323761616052121936">"Uhlelo lokusebenza luqondisiwe futhi"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> iqalisiwe."</string>
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (2953716574198046484) -->
+    <skip />
     <string name="smv_application" msgid="295583804361236288">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo lokusebenza <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
     <string name="smv_process" msgid="5120397012047462446">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> yephule inqubomgomo yokuziphoqelela Yemodi Ebukhali."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> iyasebenza"</string>
@@ -1423,4 +1429,6 @@
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
+    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b3520da..9c55627 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2522,10 +2522,10 @@
     </declare-styleable>
     <declare-styleable name="GridLayout">
         <!-- The orientation property is not used during layout. It is only used to
-        allocate row and column prameters when they are not specified by its children's
+        allocate row and column parameters when they are not specified by its children's
         layout paramters. GridLayout works like LinearLayout in this case;
         putting all the components either in a single row or in a single column -
-        depending on the value of this flag. In the horozintal case, a columnCount
+        depending on the value of this flag. In the horizontal case, a columnCount
         property may be additionally supplied to force new rows to be created when a
         row is full. The rowCount attribute may be used similarly in the vertical case.
         The default is horizontal. -->
@@ -2539,6 +2539,12 @@
         The default value is false.
         See {@link android.widget.GridLayout#setUseDefaultMargins(boolean)}.-->
         <attr name="useDefaultMargins" format="boolean" />
+        <!-- When set to true, causes alignment to take place between the outer
+        boundary of a view, as defined by its margins. When set to false,
+        causes alignment to take place between the edges of the view.
+        The default is true.
+        See {@link android.widget.GridLayout#setMarginsIncludedInAlignment(boolean)}.-->
+        <attr name="marginsIncludedInAlignment" format="boolean" />
         <!-- When set to true, forces row boundaries to appear in the same order
         as row indices.
         The default is false.
@@ -3256,9 +3262,9 @@
         <!-- The row span: the difference between the bottom and top
         boundaries delimiting the group of cells occupied by this view.
         The default is one.
-        See {@link android.widget.GridLayout.Group#span}. -->
+        See {@link android.widget.GridLayout.Group}. -->
         <attr name="layout_rowSpan" format="integer" min="1" />
-        <!-- A number indicating the relative proportion of availible space that
+        <!-- A number indicating the relative proportion of available space that
         should be taken by this group of cells.
         The default is zero.
         See {@link android.widget.GridLayout.LayoutParams#columnWeight}. -->
@@ -3269,9 +3275,9 @@
         <!-- The column span: the difference between the right and left
         boundaries delimiting the group of cells occupied by this view.
         The default is one.
-        See {@link android.widget.GridLayout.Group#span}. -->
+        See {@link android.widget.GridLayout.Group}. -->
         <attr name="layout_columnSpan" format="integer" min="1" />
-        <!-- A number indicating the relative proportion of availible space that
+        <!-- A number indicating the relative proportion of available space that
         should be taken by this group of cells.
         The default is zero.
         See {@link android.widget.GridLayout.LayoutParams#columnWeight}.-->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dba03e9..f7974e9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1043,6 +1043,17 @@
              used with this attribute are 320 for a phone screen, 600 for a
              7" tablet, and 720 for a 10" tablet. -->
         <attr name="compatibleWidthLimitDp" format="integer" />
+        <!-- Starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2},
+             this is the new way to specify the screens an application is
+             compatible with.  This attribute provides the maximum
+             "smallest screen width" (as per the -swNNNdp resource configuration)
+             that the application can work well on.  If this value is smaller than
+             the "smallest screen width" of the device it is running on, the
+             application will be forced in to screen compatibility mode with
+             no way for the user to turn it off.  Currently the compatibility mode
+             only emulates phone screens, so even if this value is larger than 320
+             the width the app runs in will be a 320 phone dimension. -->
+        <attr name="largestWidthLimitDp" format="integer" />
         <!-- Indicates whether the application supports smaller screen form-factors.
              A small screen is defined as one with a smaller aspect ratio than
              the traditional HVGA screen; that is, for a portrait screen, less
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6cdb957..81f888d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1655,6 +1655,7 @@
   <eat-comment />
   <public type="attr" name="requiresSmallestWidthDp" id="0x01010364" />
   <public type="attr" name="compatibleWidthLimitDp" />
+  <public type="attr" name="largestWidthLimitDp" />
 
 <!-- ===============================================================
      Resources added in version 13 of the platform (Ice Cream Sandwich)
@@ -1684,6 +1685,7 @@
   <public type="attr" name="columnCount" />
   <public type="attr" name="columnOrderPreserved" />
   <public type="attr" name="useDefaultMargins" />
+  <public type="attr" name="marginsIncludedInAlignment" />
 
   <public type="attr" name="layout_row" />
   <public type="attr" name="layout_rowSpan" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a277c74..8a4b74b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -711,6 +711,13 @@
         the rotation of the screen at any time. 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. [CHAR LIMIT=30] -->
+    <string name="permlab_setPointerSpeed">change pointer speed</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_setPointerSpeed">Allows an application to change
+        the mouse or trackpad pointer speed at any time. 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_signalPersistentProcesses">send Linux signals to applications</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/docs/html/guide/developing/debugging/debugging-ui.jd b/docs/html/guide/developing/debugging/debugging-ui.jd
index d2c42d5..22748be 100644
--- a/docs/html/guide/developing/debugging/debugging-ui.jd
+++ b/docs/html/guide/developing/debugging/debugging-ui.jd
@@ -31,10 +31,29 @@
         </li>
         <li><a href="#layoutopt">Optimizing Layouts with <code>layoutopt</code></a></li>
       </ol>
+      <h2>Related videos</h2>
+          <ol>
+              <li>
+<iframe title="Hierarchyviewer" 
+    width="272" height="234" 
+    src="http://www.youtube.com/embed/PAgE7saQUUY?rel=0&amp;hd=1" 
+    frameborder="0" allowfullscreen>
+</iframe>
+              </li>
+              <li>
+<iframe title="Pixel Perfect" 
+    width="272" height="234" 
+    src="http://www.youtube.com/embed/C45bMZGdN7Y?rel=0&amp;hd=1" 
+    frameborder="0" 
+    allowfullscreen>
+</iframe>
+              </li>
+          </ol>
     </div>
   </div>
 
-  <p>Sometimes your application's layout can slow down your application.
+  <p>
+Sometimes your application's layout can slow down your application.
   To help debug issues in your layout, the Android SDK provides the Hierarchy Viewer and
   <code>layoutopt</code> tools.
   </p>
diff --git a/docs/html/guide/topics/graphics/animation.jd b/docs/html/guide/topics/graphics/animation.jd
index e10ab3e..0b02ee76 100644
--- a/docs/html/guide/topics/graphics/animation.jd
+++ b/docs/html/guide/topics/graphics/animation.jd
@@ -868,10 +868,22 @@
 For more information on creating animators, see the sections on animating with
 <a href="#value-animator">ValueAnimator</a> and <a href="#object-animator">ObjectAnimator</a>
 
-  <h2 id="declaring-xml">Declaring Animations in XML</h2>
+
+<h2 id="declaring-xml">Declaring Animations in XML</h2>
 
   <p>The property animation system lets you declare property animations with XML instead of doing
-  it programmatically. The following Android classes have XML declaration support with the
+  it programmatically. By defining your animations in XML, you can easily reuse your animations
+in multiple activities and more easily edit the animation sequence.</p>
+  
+<p>To distinguish animation files that use the new property animation APIs from those that use the
+legacy <a href="{@docRoot}guide/topics/graphics/view-animation.html">view animation</a> framework,
+starting with Android 3.1, you should save the XML files for property animations in the {@code
+res/animator/} directory (instead of {@code res/anim/}). Using the {@code animator} directory name
+is optional, but necessary if you want to use the layout editor tools in the Eclipse ADT plugin (ADT
+11.0.0+), because ADT only searches the {@code res/animator/} directory for property animation
+resources.</p>
+
+<p>The following property animation classes have XML declaration support with the
   following XML tags:</p>
 
   <ul>
@@ -924,22 +936,25 @@
     beginning each time.</dd>
   </dl>
 
-  <p>The <code>objectAnimator</code> ({@link android.animation.ObjectAnimator}) element has the
-  additional attribute <code>propertyName</code>, that lets you specify the name of the property
-  being animated. The <code>objectAnimator</code> element does not expose a <code>target</code>
+  <p>The <code>&lt;objectAnimator&gt;</code> ({@link android.animation.ObjectAnimator}) element has the
+  additional attribute <code>android:propertyName</code>, that lets you specify the name of the
+property
+  being animated. The <code>&lt;objectAnimator&gt;</code> element does not expose a <code>target</code>
   attribute, however, so you cannot set the object to animate in the XML declaration. You have to
   inflate the XML resource by calling {@link android.animation.AnimatorInflater#loadAnimator
   loadAnimator()} and call {@link android.animation.ObjectAnimator#setTarget setTarget()} to set
   the target object unlike the underlying {@link android.animation.ObjectAnimator},
   before calling {@link android.animation.ObjectAnimator#start start()}.</p>
 
-  <p>The <code>set</code> element ({@link android.animation.AnimatorSet}) exposes a single
-  attribute, <code>ordering</code>. Set this attribute to <code>together</code> (default) to play
-  all the animations in this set at once. Set this attribute to <code>sequentially</code> to play
+  <p>The <code>&lt;set&gt;</code> element ({@link android.animation.AnimatorSet}) exposes a single
+  attribute, <code>android:ordering</code>. Set this attribute to <code>"together"</code> (default)
+to play
+  all the animations in this set at once. Set this attribute to <code>"sequentially"</code> to play
   the animations in the order they are declared.</p>
 
-  <p>You can specify nested <code>set</code> tags to further group animations together. The
-  animations that you want to group together should be children of the <code>set</code> tag and can
+  <p>You can specify nested <code>&lt;set&gt;</code> elements to further group animations together.
+The
+  animations that you want to group together should be children of the <code>&lt;set&gt;</code> tag and can
   define their own <code>ordering</code> attribute.</p>
 
   <p>As an example, this XML code creates an {@link android.animation.AnimatorSet} object that
@@ -969,4 +984,9 @@
   android.animation.AnimatorSet} object, and then set the target objects for all of the animations
   before starting the animation set. Calling {@link android.animation.AnimatorSet#setTarget
   setTarget()} sets a single target object for all children of the {@link
-  android.animation.AnimatorSet}.</p>
\ No newline at end of file
+  android.animation.AnimatorSet}.</p>
+
+<p class="note"><strong>Tip:</strong> To see how the ADT layout editor allows you to develop and
+preview animations in your layout, watch the <a
+href="http://www.youtube.com/watch?v=Oq05KqjXTvs&feature=player_detailpage#t=1709s">Android
+Developer Tools session</a> from Google I/O '11</p>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 32595a0..59f2e73 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -88,9 +88,18 @@
   </tr>
 
   <tr>
+    <td><code>animator/</code></td>
+    <td>XML files that define <a href="{@docRoot}guide/topics/graphics/animation.html">property
+animations</a>.</td>
+  </tr>
+
+  <tr>
     <td><code>anim/</code></td>
-    <td>XML files that define tween animations. See <a
-href="animation-resource.html">Animation Resources</a>.</td>
+    <td>XML files that define <a
+href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">tween
+animations</a>. (Property animations can also be saved in this directory, but
+the {@code animator/} directory is preferred for property animations to distinguish between the two
+types.)</td>
   </tr>
 
   <tr>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 7e13569..6f12b95 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -184,7 +184,7 @@
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?&gt;
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android">
-    &lt;item android:id="@+id/menu_add"
+    &lt;item android:id="@+id/menu_save"
           android:icon="@drawable/ic_menu_save"
           android:title="@string/menu_save"
           <b>android:showAsAction="ifRoom|withText"</b> /&gt;
diff --git a/docs/html/guide/topics/usb/index.jd b/docs/html/guide/topics/usb/index.jd
index 18af06a..3e2a18b 100644
--- a/docs/html/guide/topics/usb/index.jd
+++ b/docs/html/guide/topics/usb/index.jd
@@ -6,9 +6,9 @@
       <h2>Topics</h2>
 
       <ol>
-        <li><a href="{@docRoot}/guide/topics/USB/accessory.jd">USB Accessory</a></li>
+        <li><a href="{@docRoot}guide/topics/USB/accessory.jd">USB Accessory</a></li>
 
-        <li><a href="{@docRoot}/guide/topics/USB/host.jd">USB Host</a></li>
+        <li><a href="{@docRoot}guide/topics/USB/host.jd">USB Host</a></li>
       </ol>
     </div>
   </div>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index feb84b1..935bf63 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -1,8 +1,8 @@
 page.title=ADT Plugin for Eclipse
-adt.zip.version=10.0.1
-adt.zip.download=ADT-10.0.1.zip
-adt.zip.bytes=5096182
-adt.zip.checksum=e26a77db08377bdd2e62edeb9a3e3701
+adt.zip.version=11.0.0
+adt.zip.download=ADT-11.0.0.zip
+adt.zip.bytes=TODO
+adt.zip.checksum=TODO
 
 @jd:body
 
@@ -100,6 +100,139 @@
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
 width="9px" />
+ADT 11.0.0</a> <em>(June 2011)</em>
+  <dd class="toggleme">
+
+<dl>
+
+<dt>Dependencies:</dt>
+
+<dd>ADT 11.0.0 is designed for use with SDK Tools r11. If you haven't
+already installed SDK Tools r11 into your SDK, use the Android SDK and AVD Manager to do
+so.</dd>
+
+<dt>Visual Refactoring:</dt>
+<dd>
+  <ul>
+    <li>"Extract Style" feature pulls out style-related attributes from your layout and extracts
+them as a new style defined in {@code styles.xml} (<a
+href="http://tools.android.com/recent/extractstylerefactoring">more info</a>).</li>
+    <li>"Wrap in Container" feature lets you select a group of views then surround them
+    in a new layout (a new view group, such as a LinearLayout), and transfers namespace and layout
+    parameters to the new parent (<a
+href="http://tools.android.com/recent/newrefactoringswrapinchangelayoutchangewidget">more
+info</a>).</li>
+    <li>"Change Layout" feature changes layouts from one type
+    to another, and can also flatten a layout hierarchy (<a
+href="http://tools.android.com/recent/newrefactoringswrapinchangelayoutchangewidget">more
+info</a>).</li>
+    <li>"Change Widget Type" feature changes the type of the
+    selected views to a new type. Also, a new selection context menu
+    in the visual layout editor makes it easy to select siblings as
+    well as views anywhere in the layout that have the same type (<a
+href="http://tools.android.com/recent/newrefactoringswrapinchangelayoutchangewidget">more
+info</a>).</li>
+    <li>"Extract as Include" feature finds identical collections of views
+    in other layouts and offers to combine them into a single layout that you can then include in
+ each layout (<a
+href="http://tools.android.com/recent/extractasincludeimprovements">more info</a>).</li>
+    <li>Quick Assistant in Eclipse can be invoked
+    from the XML editor (with Ctrl-1) to apply any of the above
+    refactorings (and Extract String) to the current selection (<a
+href="http://tools.android.com/recent/refactoringquickassistant">more info</a>).</li>
+  </ul>
+</dd>
+
+<dt>Visual Layout Editor:</dt>
+<dd>
+  <ul>
+    <li>This is the update to the layout editor you've been waiting for! It includes (almost) all
+the goodies demonstrated at Google I/O. <a href="http://www.youtube.com/watch?v=Oq05KqjXTvs">Watch
+the video</a> on YouTube.</li>
+    <li>The palette now supports different configurations for supported widgets. That is, a single
+view is presented in various different configurations that you can drag into your layout. For
+example, there is a <em>Text Fields</em> palette category where you can drag an {@link
+android.widget.EditText} widget in as a password field, an e-mail field, a phone field, or other
+types of text boxes. Similarly, {@link android.widget.TextView} widgets are preconfigured
+with large, normal and small theme sizes, and {@link android.widget.LinearLayout} elements are
+preconfigured in horizontal and vertical configurations (<a
+href="http://tools.android.com/recent/multipletextfieldandlayouttypes">more info</a>).</li>
+    <li>The palette supports custom views. You can pick up any custom
+    implementations of the View class you've created in your project or from included libraries and
+drag them into your layout (<a
+href="http://tools.android.com/recent/customviewsinthepalette">more info</a>).</li>
+    <li>Fragments are available in the palette for placement in your layout. In the tool, you can
+choose which layout to show rendered for a given fragment tag. Go to declaration works for fragment
+classes (<a href="http://tools.android.com/recent/fragmentsupport">more info</a>).</li> 
+    <li>The layout editor automatically applies a "zoom to fit" for newly
+    opened files as well as on device size and orientation changes to
+    ensure that large layouts are always fully visible unless you
+    manually zoom in.</li>
+    <li>You can drop in an {@code &lt;include&gt;} element from the palette, which will pop up
+    a layout chooser. When you select the layout to include, it is added with an {@code
+&lt;include&gt;}. Similarly, dropping images or image buttons will pop up image
+    resource choosers (<a
+href="http://tools.android.com/recent/includetagdropsupport">more info</a>).</li>
+    <li>The configuration chooser now applies the "Render Target" and
+    "Locale" settings project wide, making it trivial to check the
+    layouts for different languages or render targets without having
+    to configure these individually for each layout.</li>
+    <li>The layout editor is smarter about picking a default theme to
+    render a layout with, consulting factors like theme registrations
+    in the manifest, the SDK version, and other factors.</li>
+    <li>The layout editor is smarter about picking a default configuration to render a layout
+with, defaulting to the currently visible configuration in the previous file. It also considers the
+SDK target to determine whether to default to a tablet or phone screen size.</li>
+    <li>Basic focus support. The first text field dropped in a layout is assigned focus, and there
+are <strong>Request Focus</strong> and <strong>Clear Focus</strong> context menu items on text
+fields to change the focus.</li>
+  </ul>
+</dd>
+
+<dt>XML editors:</dt>
+<dd>
+<ul>  
+  <li>Code completion has been significantly improved. It now works
+  with {@code &lt;style&gt;} elements, completes dimensional units,
+  sorts resource paths in values based on the attribute name, and more. There are also many fixes to
+handle text replacement (<a
+href="http://tools.android.com/recent/xmlcodecompletionimprovements">more info</a>).</li>
+  <li>AAPT errors are handled better. They are now underlined for the
+  relevant range in the editor, and a new quickfix makes it trivial
+  to create missing resources.</li>
+  <li>Code completion for drawable, animation and color XML files (<a
+href="http://tools.android.com/recent/codecompletionfordrawablescolorsandanimationfiles">more
+info</a>).</li>
+</ul>
+</dd>
+
+<dt>DDMS:</dt>
+<dd>
+<ul>  
+  <li>"New Folder" action in the File Explorer.</li>
+  <li>The screenshot dialog will add timestamps to the filenames and preserve the orientation on
+snapshot refresh.</li>
+</ul>
+</dd>
+
+<dt>General notes:</dt>
+<dd>
+  <ul>
+    <li>TraceView supports zooming with the mouse-wheel in the timeline.</li>
+    <li>The New Android Project wizard now supports Eclipse working sets.</li>
+  </ul>
+</dd>
+</dl>
+<p>More information about tool changes are available on the <a
+href="http://tools.android.com/recent">Android Tools Project Site</a>.</p>
+</div>
+</div>
+
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+width="9px" />
 ADT 10.0.1</a> <em>(March 2011)</em>
   <div class="toggleme">
 
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 286307a..5b90551 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -153,7 +153,7 @@
       <span style="display:none" class="zh-TW"></span>
       </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 10.0.1
+      <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 11.0.0
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
       <span style="display:none" class="fr"></span>
@@ -161,7 +161,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span></a>
-     <!-- <span class="new">new!</span> --></li>
+      <span class="new">new!</span></li>
     </ul>
   </li>
   <li>
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index bdda830..6487623 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -25,10 +25,15 @@
 public class FieldPacker {
     public FieldPacker(int len) {
         mPos = 0;
+        mLen = len;
         mData = new byte[len];
     }
 
     public void align(int v) {
+        if ((v <= 0) || ((v & (v - 1)) != 0)) {
+            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
+        }
+
         while ((mPos & (v - 1)) != 0) {
             mData[mPos++] = 0;
         }
@@ -38,11 +43,18 @@
         mPos = 0;
     }
     public void reset(int i) {
+        if ((i < 0) || (i >= mLen)) {
+            throw new RSIllegalArgumentException("out of range argument: " + i);
+        }
         mPos = i;
     }
 
     public void skip(int i) {
-        mPos += i;
+        int res = mPos + i;
+        if ((res < 0) || (res >= mLen)) {
+            throw new RSIllegalArgumentException("out of range argument: " + i);
+        }
+        mPos = res;
     }
 
     public void addI8(byte v) {
@@ -277,6 +289,7 @@
 
     private final byte mData[];
     private int mPos;
+    private int mLen;
 
 }
 
diff --git a/include/ui/Input.h b/include/ui/Input.h
index ba1c6b4..3b5aba4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -674,6 +674,87 @@
     int32_t mActivePointerId;
 };
 
+
+/*
+ * Specifies parameters that govern pointer or wheel acceleration.
+ */
+struct VelocityControlParameters {
+    // A scale factor that is multiplied with the raw velocity deltas
+    // prior to applying any other velocity control factors.  The scale
+    // factor should be used to adapt the input device resolution
+    // (eg. counts per inch) to the output device resolution (eg. pixels per inch).
+    //
+    // Must be a positive value.
+    // Default is 1.0 (no scaling).
+    float scale;
+
+    // The scaled speed at which acceleration begins to be applied.
+    // This value establishes the upper bound of a low speed regime for
+    // small precise motions that are performed without any acceleration.
+    //
+    // Must be a non-negative value.
+    // Default is 0.0 (no low threshold).
+    float lowThreshold;
+
+    // The scaled speed at which maximum acceleration is applied.
+    // The difference between highThreshold and lowThreshold controls
+    // the range of speeds over which the acceleration factor is interpolated.
+    // The wider the range, the smoother the acceleration.
+    //
+    // Must be a non-negative value greater than or equal to lowThreshold.
+    // Default is 0.0 (no high threshold).
+    float highThreshold;
+
+    // The acceleration factor.
+    // When the speed is above the low speed threshold, the velocity will scaled
+    // by an interpolated value between 1.0 and this amount.
+    //
+    // Must be a positive greater than or equal to 1.0.
+    // Default is 1.0 (no acceleration).
+    float acceleration;
+
+    VelocityControlParameters() :
+            scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
+    }
+
+    VelocityControlParameters(float scale, float lowThreshold,
+            float highThreshold, float acceleration) :
+            scale(scale), lowThreshold(lowThreshold),
+            highThreshold(highThreshold), acceleration(acceleration) {
+    }
+};
+
+/*
+ * Implements mouse pointer and wheel speed control and acceleration.
+ */
+class VelocityControl {
+public:
+    VelocityControl();
+
+    /* Sets the various parameters. */
+    void setParameters(const VelocityControlParameters& parameters);
+
+    /* Resets the current movement counters to zero.
+     * This has the effect of nullifying any acceleration. */
+    void reset();
+
+    /* Translates a raw movement delta into an appropriately
+     * scaled / accelerated delta based on the current velocity. */
+    void move(nsecs_t eventTime, float* deltaX, float* deltaY);
+
+private:
+    // If no movements are received within this amount of time,
+    // we assume the movement has stopped and reset the movement counters.
+    static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
+
+    VelocityControlParameters mParameters;
+
+    nsecs_t mLastMovementTime;
+    VelocityTracker::Position mRawPosition;
+    VelocityTracker mVelocityTracker;
+};
+
+
 /*
  * Describes the characteristics and capabilities of an input device.
  */
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 1ba38a7..e95dbe4 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -13,6 +13,10 @@
 // Log debug messages about velocity tracking.
 #define DEBUG_VELOCITY 0
 
+// Log debug messages about acceleration.
+#define DEBUG_ACCELERATION 0
+
+
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
@@ -20,6 +24,7 @@
 #include <ui/Input.h>
 
 #include <math.h>
+#include <limits.h>
 
 #ifdef HAVE_ANDROID_OS
 #include <binder/Parcel.h>
@@ -693,6 +698,11 @@
 
 // --- VelocityTracker ---
 
+const uint32_t VelocityTracker::HISTORY_SIZE;
+const nsecs_t VelocityTracker::MAX_AGE;
+const nsecs_t VelocityTracker::MIN_WINDOW;
+const nsecs_t VelocityTracker::MIN_DURATION;
+
 VelocityTracker::VelocityTracker() {
     clear();
 }
@@ -902,6 +912,85 @@
 }
 
 
+// --- VelocityControl ---
+
+const nsecs_t VelocityControl::STOP_TIME;
+
+VelocityControl::VelocityControl() {
+    reset();
+}
+
+void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
+    mParameters = parameters;
+    reset();
+}
+
+void VelocityControl::reset() {
+    mLastMovementTime = LLONG_MIN;
+    mRawPosition.x = 0;
+    mRawPosition.y = 0;
+    mVelocityTracker.clear();
+}
+
+void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
+    if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
+        if (eventTime >= mLastMovementTime + STOP_TIME) {
+#if DEBUG_ACCELERATION
+            LOGD("VelocityControl: stopped, last movement was %0.3fms ago",
+                    (eventTime - mLastMovementTime) * 0.000001f);
+#endif
+            reset();
+        }
+
+        mLastMovementTime = eventTime;
+        if (deltaX) {
+            mRawPosition.x += *deltaX;
+        }
+        if (deltaY) {
+            mRawPosition.y += *deltaY;
+        }
+        mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
+
+        float vx, vy;
+        float scale = mParameters.scale;
+        if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
+            float speed = hypotf(vx, vy) * scale;
+            if (speed >= mParameters.highThreshold) {
+                // Apply full acceleration above the high speed threshold.
+                scale *= mParameters.acceleration;
+            } else if (speed > mParameters.lowThreshold) {
+                // Linearly interpolate the acceleration to apply between the low and high
+                // speed thresholds.
+                scale *= 1 + (speed - mParameters.lowThreshold)
+                        / (mParameters.highThreshold - mParameters.lowThreshold)
+                        * (mParameters.acceleration - 1);
+            }
+
+#if DEBUG_ACCELERATION
+            LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
+                    "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+                    mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+                    mParameters.acceleration,
+                    vx, vy, speed, scale / mParameters.scale);
+#endif
+        } else {
+#if DEBUG_ACCELERATION
+            LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
+                    mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+                    mParameters.acceleration);
+#endif
+        }
+
+        if (deltaX) {
+            *deltaX *= scale;
+        }
+        if (deltaY) {
+            *deltaY *= scale;
+        }
+    }
+}
+
+
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index bf06f947..2e2768f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -125,4 +125,7 @@
     <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS -->
     <integer name="def_long_press_timeout_millis">500</integer>
 
+    <!-- Default for Settings.System.POINTER_SPEED -->
+    <integer name="def_pointer_speed">0</integer>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b99c8b0..0f5f095 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1214,6 +1214,9 @@
             loadBooleanSetting(stmt, Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
                     R.bool.def_notifications_use_ring_volume);
 
+            loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,
+                    R.integer.def_pointer_speed);
+
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/packages/SystemUI/res/values-fr-large/strings.xml b/packages/SystemUI/res/values-fr-large/strings.xml
index 447b174..f8dd55e 100644
--- a/packages/SystemUI/res/values-fr-large/strings.xml
+++ b/packages/SystemUI/res/values-fr-large/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Tout effacer"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Aucune connexion"</string>
-    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Connecté au Wi-Fi."</string>
+    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="4467935186864208249">"Recherche de GPS en cours"</string>
     <string name="gps_notification_found_text" msgid="6270628388918822956">"Position définie par GPS"</string>
     <string name="notifications_off_title" msgid="1860117696034775851">"Notifications désactivées"</string>
diff --git a/packages/SystemUI/res/values-it-large/strings.xml b/packages/SystemUI/res/values-it-large/strings.xml
index 3cde529..18ccd07 100644
--- a/packages/SystemUI/res/values-it-large/strings.xml
+++ b/packages/SystemUI/res/values-it-large/strings.xml
@@ -19,8 +19,8 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Cancella tutto"</string>
-    <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna conness. Internet"</string>
+    <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Cancella"</string>
+    <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna connessione"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi connesso"</string>
     <string name="gps_notification_searching_text" msgid="4467935186864208249">"Ricerca del GPS"</string>
     <string name="gps_notification_found_text" msgid="6270628388918822956">"Posizione stabilita dal GPS"</string>
diff --git a/packages/SystemUI/res/values-ru-large/strings.xml b/packages/SystemUI/res/values-ru-large/strings.xml
index c48321e..bafb97f 100644
--- a/packages/SystemUI/res/values-ru-large/strings.xml
+++ b/packages/SystemUI/res/values-ru-large/strings.xml
@@ -19,11 +19,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Очистить"</string>
+    <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Очистить все"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Нет подключения к Интернету"</string>
-    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi: подключено"</string>
-    <string name="gps_notification_searching_text" msgid="4467935186864208249">"Выполняется поиск при помощи GPS"</string>
+    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi подключено"</string>
+    <string name="gps_notification_searching_text" msgid="4467935186864208249">"Поиск GPS"</string>
     <string name="gps_notification_found_text" msgid="6270628388918822956">"Местоположение установлено с помощью GPS"</string>
-    <string name="notifications_off_title" msgid="1860117696034775851">"Показ уведомлений отключен"</string>
-    <string name="notifications_off_text" msgid="1439152806320786912">"Нажмите здесь, чтобы снова разрешить показ уведомлений."</string>
+    <string name="notifications_off_title" msgid="1860117696034775851">"Уведомления отключены"</string>
+    <string name="notifications_off_text" msgid="1439152806320786912">"Нажмите здесь, чтобы снова включить уведомления."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml
new file mode 100644
index 0000000..ab7661a
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp-port/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <integer name="config_maxNotificationIcons">3</integer>
+</resources>
+
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 78dd8c4..b8a6cfe 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (c) 2010, The Android Open Source Project
+ * Copyright (c) 2011, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); 
  * you may not use this file except in compliance with the License. 
@@ -17,6 +17,6 @@
 -->
 <resources>
     <!-- gap on either side of status bar notification icons -->
-    <dimen name="status_bar_icon_padding">2dp</dimen>
+    <dimen name="status_bar_icon_padding">0dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
new file mode 100644
index 0000000..74b266d
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+    <!-- gap on either side of status bar notification icons -->
+    <dimen name="status_bar_icon_padding">2dp</dimen>
+</resources>
+
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
new file mode 100644
index 0000000..56b8e54
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <integer name="config_maxNotificationIcons">5</integer>
+</resources>
+
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 48f572f..7a4ac5d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -40,5 +40,8 @@
          autodetected from the Configuration. -->
     <bool name="config_showNavigationBar">false</bool>
 
+    <!-- How many icons may be shown at once in the system bar. Includes any
+         slots that may be reused for things like IME control. -->
+    <integer name="config_maxNotificationIcons">5</integer>
 </resources>
 
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 8750a6f..5b5801d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -81,9 +81,6 @@
     public static final boolean DEBUG = false;
     public static final String TAG = "TabletStatusBar";
 
-    public static final int MAX_NOTIFICATION_ICONS = 5;
-    // IME switcher icon is big and occupy width of two icons
-    public static final int MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE = MAX_NOTIFICATION_ICONS - 1;
 
     public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
     public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
@@ -105,6 +102,7 @@
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
     int mIconHPadding = -1;
+    private int mMaxNotificationIcons = 5;
 
     H mHandler = new H();
 
@@ -311,7 +309,7 @@
         final Resources res = mContext.getResources();
         final Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
         return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height),
-                d.getHeight());
+                d.getRealHeight());
     }
 
     @Override
@@ -344,6 +342,13 @@
             mIconSize = newIconSize;
             reloadAllNotificationIcons(); // reload the tray
         }
+
+        final int numIcons = res.getInteger(R.integer.config_maxNotificationIcons);
+        if (numIcons != mMaxNotificationIcons) {
+            mMaxNotificationIcons = numIcons;
+            if (DEBUG) Slog.d(TAG, "max notification icons: " + mMaxNotificationIcons);
+            reloadAllNotificationIcons();
+        }
     }
 
     protected View makeStatusBarView() {
@@ -1430,9 +1435,11 @@
 
         // When IME button is visible, the number of notification icons should be decremented
         // to fit the upper limit.
+        // IME switcher icon is big and occupy width of one icon
+        final int maxNotificationIconsImeButtonVisible = mMaxNotificationIcons - 1;
         final int maxNotificationIconsCount =
                 (mInputMethodSwitchButton.getVisibility() != View.GONE) ?
-                        MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE : MAX_NOTIFICATION_ICONS;
+                        maxNotificationIconsImeButtonVisible : mMaxNotificationIcons;
         for (int i=0; i< maxNotificationIconsCount; i++) {
             if (i>=N) break;
             toShow.add(mNotificationData.get(N-i-1).icon);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index ae23df6..7983278 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Canvas;
 import android.util.Log;
@@ -94,6 +95,8 @@
     public synchronized void show() {
         if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
 
+        Resources res = mContext.getResources();
+        boolean enableScreenRotation = res.getBoolean(R.bool.config_enableLockScreenRotation);
         if (mKeyguardHost == null) {
             if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
 
@@ -116,18 +119,22 @@
             lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
             lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
 
-            // TODO: Sometimes we get the wrong value for the sensor resource we use to configure
-            // this.  However, the current UI design has LockScreen always respond to orientation so
-            // we don't need this for the time-being.
-            //
-            // For reference, the configuration variable is R.bool.config_enableLockScreenRotation
-            lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
             lp.setTitle("Keyguard");
             mWindowLayoutParams = lp;
 
             mViewManager.addView(mKeyguardHost, lp);
         }
 
+        if (enableScreenRotation) {
+            Log.d(TAG, "Rotation sensor for lock screen On!");
+            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
+        } else {
+            Log.d(TAG, "Rotation sensor for lock screen Off!");
+            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        }
+
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+
         if (mKeyguardView == null) {
             if (DEBUG) Log.d(TAG, "keyguard view is null, creating it...");
             mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 57b6b5e..6734005 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -125,7 +125,8 @@
             mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
                     | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
         } else {
-            mPasswordEntry.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+            mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
+                    | InputType.TYPE_TEXT_VARIATION_PASSWORD);
         }
 
         mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6eaba21..8520219 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -30,6 +30,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -781,8 +782,9 @@
         // Determine whether the status bar can hide based on the size
         // of the screen.  We assume sizes > 600dp are tablets where we
         // will use the system bar.
-        int shortSizeDp = (shortSize*DisplayMetrics.DENSITY_DEVICE)
-                / DisplayMetrics.DENSITY_DEFAULT;
+        int shortSizeDp = shortSize
+                * DisplayMetrics.DENSITY_DEFAULT
+                / DisplayMetrics.DENSITY_DEVICE;
         mStatusBarCanHide = shortSizeDp < 600;
         mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
                 mStatusBarCanHide
@@ -1125,9 +1127,9 @@
     }
     
     /** {@inheritDoc} */
-    public View addStartingWindow(IBinder appToken, String packageName,
-                                  int theme, CharSequence nonLocalizedLabel,
-                                  int labelRes, int icon, int windowFlags) {
+    public View addStartingWindow(IBinder appToken, String packageName, int theme,
+            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
+            int icon, int windowFlags) {
         if (!SHOW_STARTING_ANIMATIONS) {
             return null;
         }
@@ -1173,8 +1175,12 @@
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
     
+            if (!compatInfo.supportsScreen()) {
+                win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
+            }
+
             win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
-                                WindowManager.LayoutParams.MATCH_PARENT);
+                    WindowManager.LayoutParams.MATCH_PARENT);
     
             final WindowManager.LayoutParams params = win.getAttributes();
             params.token = appToken;
@@ -1947,28 +1953,41 @@
                     Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
                 // Otherwise, a normal window must be placed inside the content
                 // of all screen decorations.
-                pf.left = mContentLeft;
-                pf.top = mContentTop;
-                pf.right = mContentRight;
-                pf.bottom = mContentBottom;
-                if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                    df.left = cf.left = mDockLeft;
-                    df.top = cf.top = mDockTop;
-                    df.right = cf.right = mDockRight;
-                    df.bottom = cf.bottom = mDockBottom;
+                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+                    // Status bar panels are the only windows who can go on top of
+                    // the status bar.  They are protected by the STATUS_BAR_SERVICE
+                    // permission, so they have the same privileges as the status
+                    // bar itself.
+                    pf.left = df.left = cf.left = vf.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = cf.top = vf.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = cf.right = vf.right
+                            = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = cf.bottom = vf.bottom
+                            = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
                 } else {
-                    df.left = cf.left = mContentLeft;
-                    df.top = cf.top = mContentTop;
-                    df.right = cf.right = mContentRight;
-                    df.bottom = cf.bottom = mContentBottom;
-                }
-                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
-                    vf.left = mCurLeft;
-                    vf.top = mCurTop;
-                    vf.right = mCurRight;
-                    vf.bottom = mCurBottom;
-                } else {
-                    vf.set(cf);
+                    pf.left = mContentLeft;
+                    pf.top = mContentTop;
+                    pf.right = mContentRight;
+                    pf.bottom = mContentBottom;
+                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                        df.left = cf.left = mDockLeft;
+                        df.top = cf.top = mDockTop;
+                        df.right = cf.right = mDockRight;
+                        df.bottom = cf.bottom = mDockBottom;
+                    } else {
+                        df.left = cf.left = mContentLeft;
+                        df.top = cf.top = mContentTop;
+                        df.right = cf.right = mContentRight;
+                        df.bottom = cf.bottom = mContentBottom;
+                    }
+                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                        vf.left = mCurLeft;
+                        vf.top = mCurTop;
+                        vf.right = mCurRight;
+                        vf.bottom = mCurBottom;
+                    } else {
+                        vf.set(cf);
+                    }
                 }
             }
         }
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index af30887..29add52 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -33,6 +33,7 @@
 
 #include <hardware_legacy/power.h>
 
+#include <cutils/atomic.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
@@ -128,6 +129,7 @@
         mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
         mOpeningDevices(0), mClosingDevices(0),
         mOpened(false), mNeedToSendFinishedDeviceScan(false),
+        mNeedToReopenDevices(0), mNeedToScanDevices(false),
         mInputFdIndex(1) {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
@@ -393,12 +395,10 @@
     return NAME_NOT_FOUND;
 }
 
-void EventHub::addExcludedDevice(const char* deviceName)
-{
+void EventHub::setExcludedDevices(const Vector<String8>& devices) {
     AutoMutex _l(mLock);
 
-    String8 name(deviceName);
-    mExcludedDevices.push_back(name);
+    mExcludedDevices = devices;
 }
 
 bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
@@ -466,9 +466,11 @@
     LOG_ASSERT(bufferSize >= 1);
 
     if (!mOpened) {
+        android_atomic_acquire_store(0, &mNeedToReopenDevices);
+
         mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
         mOpened = true;
-        mNeedToSendFinishedDeviceScan = true;
+        mNeedToScanDevices = true;
     }
 
     struct input_event readBuffer[bufferSize];
@@ -478,6 +480,20 @@
     for (;;) {
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
+        // Reopen input devices if needed.
+        if (android_atomic_acquire_load(&mNeedToReopenDevices)) {
+            android_atomic_acquire_store(0, &mNeedToReopenDevices);
+
+            LOGI("Reopening all input devices due to a configuration change.");
+
+            AutoMutex _l(mLock);
+            while (mDevices.size() > 1) {
+                closeDeviceAtIndexLocked(mDevices.size() - 1);
+            }
+            mNeedToScanDevices = true;
+            break; // return to the caller before we actually rescan
+        }
+
         // Report any devices that had last been added/removed.
         while (mClosingDevices) {
             Device* device = mClosingDevices;
@@ -495,6 +511,12 @@
             }
         }
 
+        if (mNeedToScanDevices) {
+            mNeedToScanDevices = false;
+            scanDevices();
+            mNeedToSendFinishedDeviceScan = true;
+        }
+
         while (mOpeningDevices != NULL) {
             Device* device = mOpeningDevices;
             LOGV("Reporting device opened: id=%d, name=%s\n",
@@ -696,13 +718,14 @@
     pollfd.revents = 0;
     mFds.push(pollfd);
     mDevices.push(NULL);
+    return true;
+}
 
-    res = scanDir(DEVICE_PATH);
+void EventHub::scanDevices() {
+    int res = scanDir(DEVICE_PATH);
     if(res < 0) {
         LOGE("scan dir failed for %s\n", DEVICE_PATH);
     }
-
-    return true;
 }
 
 // ----------------------------------------------------------------------------
@@ -755,12 +778,10 @@
     }
 
     // Check to see if the device is on our excluded list
-    List<String8>::iterator iter = mExcludedDevices.begin();
-    List<String8>::iterator end = mExcludedDevices.end();
-    for ( ; iter != end; iter++) {
-        const char* test = *iter;
-        if (identifier.name == test) {
-            LOGI("ignoring event id %s driver %s\n", devicePath, test);
+    for (size_t i = 0; i < mExcludedDevices.size(); i++) {
+        const String8& item = mExcludedDevices.itemAt(i);
+        if (identifier.name == item) {
+            LOGI("ignoring event id %s driver %s\n", devicePath, item.string());
             close(fd);
             return -1;
         }
@@ -1223,6 +1244,10 @@
     return 0;
 }
 
+void EventHub::reopenDevices() {
+    android_atomic_release_store(1, &mNeedToReopenDevices);
+}
+
 void EventHub::dump(String8& dump) {
     dump.append("Event Hub State:\n");
 
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index ca33619..558959b 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -193,9 +193,9 @@
     virtual status_t mapAxis(int32_t deviceId, int scancode,
             AxisInfo* outAxisInfo) const = 0;
 
-    // exclude a particular device from opening
-    // this can be used to ignore input devices for sensors
-    virtual void addExcludedDevice(const char* deviceName) = 0;
+    // Sets devices that are excluded from opening.
+    // This can be used to ignore input devices for sensors.
+    virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
 
     /*
      * Wait for events to become available and returns them.
@@ -230,6 +230,8 @@
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
             Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
 
+    virtual void reopenDevices() = 0;
+
     virtual void dump(String8& dump) = 0;
 };
 
@@ -259,7 +261,7 @@
     virtual status_t mapAxis(int32_t deviceId, int scancode,
             AxisInfo* outAxisInfo) const;
 
-    virtual void addExcludedDevice(const char* deviceName);
+    virtual void setExcludedDevices(const Vector<String8>& devices);
 
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
     virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
@@ -276,6 +278,8 @@
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
             Vector<VirtualKeyDefinition>& outVirtualKeys) const;
 
+    virtual void reopenDevices();
+
     virtual void dump(String8& dump);
 
 protected:
@@ -288,6 +292,7 @@
     int closeDevice(const char *devicePath);
     int closeDeviceAtIndexLocked(int index);
     int scanDir(const char *dirname);
+    void scanDevices();
     int readNotify(int nfd);
 
     status_t mError;
@@ -351,7 +356,9 @@
 
     bool mOpened;
     bool mNeedToSendFinishedDeviceScan;
-    List<String8> mExcludedDevices;
+    volatile int32_t mNeedToReopenDevices; // must be modified atomically
+    bool mNeedToScanDevices;
+    Vector<String8> mExcludedDevices;
 
     // device ids that report particular switches.
     int32_t mSwitches[SW_MAX + 1];
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 8c535d6..4c6098d 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -228,13 +228,14 @@
 
     mKeyRepeatState.lastKeyEntry = NULL;
 
-    int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond();
-    mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond;
+    policy->getDispatcherConfiguration(&mConfig);
+
+    mThrottleState.minTimeBetweenEvents = 1000000000LL / mConfig.maxEventsPerSecond;
     mThrottleState.lastDeviceId = -1;
 
 #if DEBUG_THROTTLING
     mThrottleState.originalSampleCount = 0;
-    LOGD("Throttling - Max events per second = %d", maxEventsPerSecond);
+    LOGD("Throttling - Max events per second = %d", mConfig.maxEventsPerSecond);
 #endif
 }
 
@@ -253,13 +254,10 @@
 }
 
 void InputDispatcher::dispatchOnce() {
-    nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
-    nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
-
     nsecs_t nextWakeupTime = LONG_LONG_MAX;
     { // acquire lock
         AutoMutex _l(mLock);
-        dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
+        dispatchOnceInnerLocked(&nextWakeupTime);
 
         if (runCommandsLockedInterruptible()) {
             nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
@@ -272,14 +270,13 @@
     mLooper->pollOnce(timeoutMillis);
 }
 
-void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
-        nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) {
+void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
     nsecs_t currentTime = now();
 
     // Reset the key repeat timer whenever we disallow key events, even if the next event
     // is not a key.  This is to ensure that we abort a key repeat if the device is just coming
     // out of sleep.
-    if (keyRepeatTimeout < 0) {
+    if (!mPolicy->isKeyRepeatEnabled()) {
         resetKeyRepeatLocked();
     }
 
@@ -313,7 +310,7 @@
             // Synthesize a key repeat if appropriate.
             if (mKeyRepeatState.lastKeyEntry) {
                 if (currentTime >= mKeyRepeatState.nextRepeatTime) {
-                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime, keyRepeatDelay);
+                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
                 } else {
                     if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
                         *nextWakeupTime = mKeyRepeatState.nextRepeatTime;
@@ -432,8 +429,7 @@
         if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
             dropReason = DROP_REASON_BLOCKED;
         }
-        done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
-                &dropReason, nextWakeupTime);
+        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
         break;
     }
 
@@ -692,8 +688,7 @@
     }
 }
 
-InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(
-        nsecs_t currentTime, nsecs_t keyRepeatDelay) {
+InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
     KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
 
     // Reuse the repeated key entry if it is otherwise unreferenced.
@@ -721,7 +716,7 @@
     // mKeyRepeatState.lastKeyEntry in addition to the one we return.
     entry->refCount += 1;
 
-    mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatDelay;
+    mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay;
     return entry;
 }
 
@@ -741,8 +736,7 @@
     return true;
 }
 
-bool InputDispatcher::dispatchKeyLocked(
-        nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
+bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
         DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Preprocessing.
     if (! entry->dispatchInProgress) {
@@ -762,7 +756,7 @@
             } else {
                 // Not a repeat.  Save key down state in case we do see a repeat later.
                 resetKeyRepeatLocked();
-                mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout;
+                mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
             }
             mKeyRepeatState.lastKeyEntry = entry;
             entry->refCount += 1;
@@ -3777,6 +3771,11 @@
 void InputDispatcher::dump(String8& dump) {
     dump.append("Input Dispatcher State:\n");
     dumpDispatchStateLocked(dump);
+
+    dump.append(INDENT "Configuration:\n");
+    dump.appendFormat(INDENT2 "MaxEventsPerSecond: %d\n", mConfig.maxEventsPerSecond);
+    dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f);
+    dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f);
 }
 
 
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 9ac5b75..37cef90 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -143,6 +143,30 @@
 
 
 /*
+ * Input dispatcher configuration.
+ *
+ * Specifies various options that modify the behavior of the input dispatcher.
+ */
+struct InputDispatcherConfiguration {
+    // The key repeat initial timeout.
+    nsecs_t keyRepeatTimeout;
+
+    // The key repeat inter-key delay.
+    nsecs_t keyRepeatDelay;
+
+    // The maximum suggested event delivery rate per second.
+    // This value is used to throttle motion event movement actions on a per-device
+    // basis.  It is not intended to be a hard limit.
+    int32_t maxEventsPerSecond;
+
+    InputDispatcherConfiguration() :
+            keyRepeatTimeout(500 * 1000000LL),
+            keyRepeatDelay(50 * 1000000LL),
+            maxEventsPerSecond(60) { }
+};
+
+
+/*
  * Input dispatcher policy interface.
  *
  * The input reader policy is used by the input reader to interact with the Window Manager
@@ -168,17 +192,11 @@
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
 
-    /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */
-    virtual nsecs_t getKeyRepeatTimeout() = 0;
+    /* Gets the input dispatcher configuration. */
+    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
 
-    /* Gets the key repeat inter-key delay. */
-    virtual nsecs_t getKeyRepeatDelay() = 0;
-
-    /* Gets the maximum suggested event delivery rate per second.
-     * This value is used to throttle motion event movement actions on a per-device
-     * basis.  It is not intended to be a hard limit.
-     */
-    virtual int32_t getMaxEventsPerSecond() = 0;
+    /* Returns true if automatic key repeating is enabled. */
+    virtual bool isKeyRepeatEnabled() = 0;
 
     /* Filters an input event.
      * Return true to dispatch the event unmodified, false to consume the event.
@@ -800,6 +818,7 @@
     };
 
     sp<InputDispatcherPolicyInterface> mPolicy;
+    InputDispatcherConfiguration mConfig;
 
     Mutex mLock;
 
@@ -812,8 +831,7 @@
 
     Vector<EventEntry*> mTempCancelationEvents;
 
-    void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
-            nsecs_t* nextWakeupTime);
+    void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
 
     // Batches a new sample onto a motion entry.
     // Assumes that the we have already checked that we can append samples.
@@ -885,7 +903,7 @@
     } mKeyRepeatState;
 
     void resetKeyRepeatLocked();
-    KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime, nsecs_t keyRepeatTimeout);
+    KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime);
 
     // Deferred command processing.
     bool runCommandsLockedInterruptible();
@@ -943,7 +961,7 @@
     bool dispatchConfigurationChangedLocked(
             nsecs_t currentTime, ConfigurationChangedEntry* entry);
     bool dispatchKeyLocked(
-            nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
+            nsecs_t currentTime, KeyEntry* entry,
             DropReason* dropReason, nsecs_t* nextWakeupTime);
     bool dispatchMotionLocked(
             nsecs_t currentTime, MotionEntry* entry,
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 35e08d4..c42e3ab 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -38,6 +38,7 @@
 
 #include "InputReader.h"
 
+#include <cutils/atomic.h>
 #include <cutils/log.h>
 #include <ui/Keyboard.h>
 #include <ui/VirtualKeyMap.h>
@@ -61,65 +62,6 @@
 // Maximum number of slots supported when using the slot-based Multitouch Protocol B.
 static const size_t MAX_SLOTS = 32;
 
-// Quiet time between certain gesture transitions.
-// Time to allow for all fingers or buttons to settle into a stable state before
-// starting a new gesture.
-static const nsecs_t QUIET_INTERVAL = 100 * 1000000; // 100 ms
-
-// The minimum speed that a pointer must travel for us to consider switching the active
-// touch pointer to it during a drag.  This threshold is set to avoid switching due
-// to noise from a finger resting on the touch pad (perhaps just pressing it down).
-static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second
-
-// Tap gesture delay time.
-// The time between down and up must be less than this to be considered a tap.
-static const nsecs_t TAP_INTERVAL = 150 * 1000000; // 150 ms
-
-// Tap drag gesture delay time.
-// The time between up and the next up must be greater than this to be considered a
-// drag.  Otherwise, the previous tap is finished and a new tap begins.
-static const nsecs_t TAP_DRAG_INTERVAL = 150 * 1000000; // 150 ms
-
-// The distance in pixels that the pointer is allowed to move from initial down
-// to up and still be called a tap.
-static const float TAP_SLOP = 10.0f; // 10 pixels
-
-// Time after the first touch points go down to settle on an initial centroid.
-// This is intended to be enough time to handle cases where the user puts down two
-// fingers at almost but not quite exactly the same time.
-static const nsecs_t MULTITOUCH_SETTLE_INTERVAL = 100 * 1000000; // 100ms
-
-// The transition from PRESS to SWIPE or FREEFORM gesture mode is made when
-// both of the pointers are moving at least this fast.
-static const float MULTITOUCH_MIN_SPEED = 150.0f; // pixels per second
-
-// The transition from PRESS to SWIPE gesture mode can only occur when the
-// cosine of the angle between the two vectors is greater than or equal to than this value
-// which indicates that the vectors are oriented in the same direction.
-// When the vectors are oriented in the exactly same direction, the cosine is 1.0.
-// (In exactly opposite directions, the cosine is -1.0.)
-static const float SWIPE_TRANSITION_ANGLE_COSINE = 0.5f; // cosine of 45 degrees
-
-// The transition from PRESS to SWIPE gesture mode can only occur when the
-// fingers are no more than this far apart relative to the diagonal size of
-// the touch pad.  For example, a ratio of 0.5 means that the fingers must be
-// no more than half the diagonal size of the touch pad apart.
-static const float SWIPE_MAX_WIDTH_RATIO = 0.333f; // 1/3
-
-// The gesture movement speed factor relative to the size of the display.
-// Movement speed applies when the fingers are moving in the same direction.
-// Without acceleration, a full swipe of the touch pad diagonal in movement mode
-// will cover this portion of the display diagonal.
-static const float GESTURE_MOVEMENT_SPEED_RATIO = 0.8f;
-
-// The gesture zoom speed factor relative to the size of the display.
-// Zoom speed applies when the fingers are mostly moving relative to each other
-// to execute a scale gesture or similar.
-// Without acceleration, a full swipe of the touch pad diagonal in zoom mode
-// will cover this portion of the display diagonal.
-static const float GESTURE_ZOOM_SPEED_RATIO = 0.3f;
-
-
 // --- Static Functions ---
 
 template<typename T>
@@ -319,8 +261,9 @@
         const sp<InputReaderPolicyInterface>& policy,
         const sp<InputDispatcherInterface>& dispatcher) :
         mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
-        mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) {
-    configureExcludedDevices();
+        mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
+        mRefreshConfiguration(0) {
+    configure(true /*firstTime*/);
     updateGlobalMetaState();
     updateInputConfiguration();
 }
@@ -332,6 +275,11 @@
 }
 
 void InputReader::loopOnce() {
+    if (android_atomic_acquire_load(&mRefreshConfiguration)) {
+        android_atomic_release_store(0, &mRefreshConfiguration);
+        configure(false /*firstTime*/);
+    }
+
     int32_t timeoutMillis = -1;
     if (mNextTimeout != LLONG_MAX) {
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -552,12 +500,12 @@
     mDispatcher->notifyConfigurationChanged(when);
 }
 
-void InputReader::configureExcludedDevices() {
-    Vector<String8> excludedDeviceNames;
-    mPolicy->getExcludedDeviceNames(excludedDeviceNames);
+void InputReader::configure(bool firstTime) {
+    mPolicy->getReaderConfiguration(&mConfig);
+    mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
 
-    for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
-        mEventHub->addExcludedDevice(excludedDeviceNames[i]);
+    if (!firstTime) {
+        mEventHub->reopenDevices();
     }
 }
 
@@ -778,6 +726,10 @@
     } // release device registy reader lock
 }
 
+void InputReader::refreshConfiguration() {
+    android_atomic_release_store(1, &mRefreshConfiguration);
+}
+
 void InputReader::dump(String8& dump) {
     mEventHub->dump(dump);
     dump.append("\n");
@@ -791,6 +743,60 @@
             mDevices.valueAt(i)->dump(dump);
         }
     } // release device registy reader lock
+
+    dump.append(INDENT "Configuration:\n");
+    dump.append(INDENT2 "ExcludedDeviceNames: [");
+    for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
+        if (i != 0) {
+            dump.append(", ");
+        }
+        dump.append(mConfig.excludedDeviceNames.itemAt(i).string());
+    }
+    dump.append("]\n");
+    dump.appendFormat(INDENT2 "FilterTouchEvents: %s\n",
+            toString(mConfig.filterTouchEvents));
+    dump.appendFormat(INDENT2 "FilterJumpyTouchEvents: %s\n",
+            toString(mConfig.filterJumpyTouchEvents));
+    dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
+            mConfig.virtualKeyQuietTime * 0.000001f);
+
+    dump.appendFormat(INDENT2 "PointerVelocityControlParameters: "
+            "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
+            mConfig.pointerVelocityControlParameters.scale,
+            mConfig.pointerVelocityControlParameters.lowThreshold,
+            mConfig.pointerVelocityControlParameters.highThreshold,
+            mConfig.pointerVelocityControlParameters.acceleration);
+
+    dump.appendFormat(INDENT2 "WheelVelocityControlParameters: "
+            "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
+            mConfig.wheelVelocityControlParameters.scale,
+            mConfig.wheelVelocityControlParameters.lowThreshold,
+            mConfig.wheelVelocityControlParameters.highThreshold,
+            mConfig.wheelVelocityControlParameters.acceleration);
+
+    dump.appendFormat(INDENT2 "PointerGesture:\n");
+    dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n",
+            mConfig.pointerGestureQuietInterval * 0.000001f);
+    dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
+            mConfig.pointerGestureDragMinSwitchSpeed);
+    dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n",
+            mConfig.pointerGestureTapInterval * 0.000001f);
+    dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n",
+            mConfig.pointerGestureTapDragInterval * 0.000001f);
+    dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n",
+            mConfig.pointerGestureTapSlop);
+    dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
+            mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
+    dump.appendFormat(INDENT3 "MultitouchMinSpeed: %0.1fpx/s\n",
+            mConfig.pointerGestureMultitouchMinSpeed);
+    dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
+            mConfig.pointerGestureSwipeTransitionAngleCosine);
+    dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
+            mConfig.pointerGestureSwipeMaxWidthRatio);
+    dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n",
+            mConfig.pointerGestureMovementSpeedRatio);
+    dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
+            mConfig.pointerGestureZoomSpeedRatio);
 }
 
 
@@ -1450,6 +1456,10 @@
 
     mHaveVWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_WHEEL);
     mHaveHWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_HWHEEL);
+
+    mPointerVelocityControl.setParameters(getConfig()->pointerVelocityControlParameters);
+    mWheelXVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters);
+    mWheelYVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters);
 }
 
 void CursorInputMapper::configureParameters() {
@@ -1511,6 +1521,11 @@
             }
         } // release lock
 
+        // Reset velocity.
+        mPointerVelocityControl.reset();
+        mWheelXVelocityControl.reset();
+        mWheelYVelocityControl.reset();
+
         // Synthesize button up event on reset.
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
         mAccumulator.clear();
@@ -1674,11 +1689,16 @@
         } else {
             vscroll = 0;
         }
+        mWheelYVelocityControl.move(when, NULL, &vscroll);
+
         if (mHaveHWheel && (fields & Accumulator::FIELD_REL_HWHEEL)) {
             hscroll = mAccumulator.relHWheel;
         } else {
             hscroll = 0;
         }
+        mWheelXVelocityControl.move(when, &hscroll, NULL);
+
+        mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
         if (mPointerController != NULL) {
             if (deltaX != 0 || deltaY != 0 || vscroll != 0 || hscroll != 0
@@ -1782,6 +1802,8 @@
 
 TouchInputMapper::TouchInputMapper(InputDevice* device) :
         InputMapper(device) {
+    mConfig = getConfig();
+
     mLocked.surfaceOrientation = -1;
     mLocked.surfaceWidth = -1;
     mLocked.surfaceHeight = -1;
@@ -1918,6 +1940,7 @@
     mLocked.orientedRanges.haveDistance = false;
 
     mPointerGesture.reset();
+    mPointerGesture.pointerVelocityControl.setParameters(mConfig->pointerVelocityControlParameters);
 }
 
 void TouchInputMapper::configure() {
@@ -1960,14 +1983,15 @@
 }
 
 void TouchInputMapper::configureParameters() {
-    mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
-    mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
-    mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
-    mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime();
+    mParameters.useBadTouchFilter = mConfig->filterTouchEvents;
+    mParameters.useAveragingTouchFilter = mConfig->filterTouchEvents;
+    mParameters.useJumpyTouchFilter = mConfig->filterJumpyTouchEvents;
 
-    // TODO: select the default gesture mode based on whether the device supports
-    // distinct multitouch
-    mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;
+    // Use the pointer presentation mode for devices that do not support distinct
+    // multitouch.  The spot-based presentation relies on being able to accurately
+    // locate two or more fingers on the touch pad.
+    mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT)
+            ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS;
 
     String8 gestureModeString;
     if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
@@ -2388,26 +2412,26 @@
                     mLocked.associatedDisplayHeight);
 
             // Scale movements such that one whole swipe of the touch pad covers a
-            // given area relative to the diagonal size of the display.
+            // given area relative to the diagonal size of the display when no acceleration
+            // is applied.
             // Assume that the touch pad has a square aspect ratio such that movements in
             // X and Y of the same number of raw units cover the same physical distance.
-            const float scaleFactor = 0.8f;
-
-            mLocked.pointerGestureXMovementScale = GESTURE_MOVEMENT_SPEED_RATIO
+            mLocked.pointerGestureXMovementScale = mConfig->pointerGestureMovementSpeedRatio
                     * displayDiagonal / rawDiagonal;
             mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale;
 
             // Scale zooms to cover a smaller range of the display than movements do.
             // This value determines the area around the pointer that is affected by freeform
             // pointer gestures.
-            mLocked.pointerGestureXZoomScale = GESTURE_ZOOM_SPEED_RATIO
+            mLocked.pointerGestureXZoomScale = mConfig->pointerGestureZoomSpeedRatio
                     * displayDiagonal / rawDiagonal;
             mLocked.pointerGestureYZoomScale = mLocked.pointerGestureXZoomScale;
 
             // Max width between pointers to detect a swipe gesture is more than some fraction
             // of the diagonal axis of the touch pad.  Touches that are wider than this are
             // translated into freeform gestures.
-            mLocked.pointerGestureMaxSwipeWidth = SWIPE_MAX_WIDTH_RATIO * rawDiagonal;
+            mLocked.pointerGestureMaxSwipeWidth =
+                    mConfig->pointerGestureSwipeMaxWidthRatio * rawDiagonal;
 
             // Reset the current pointer gesture.
             mPointerGesture.reset();
@@ -3130,8 +3154,8 @@
     //    area and accidentally triggers a virtual key.  This often happens when virtual keys
     //    are layed out below the screen near to where the on screen keyboard's space bar
     //    is displayed.
-    if (mParameters.virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) {
-        mContext->disableVirtualKeysUntil(when + mParameters.virtualKeyQuietTime);
+    if (mConfig->virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) {
+        mContext->disableVirtualKeysUntil(when + mConfig->virtualKeyQuietTime);
     }
 }
 
@@ -3474,12 +3498,6 @@
 
 void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags,
         bool isTimeout) {
-    // Switch pointer presentation.
-    mPointerController->setPresentation(
-            mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
-                    ? PointerControllerInterface::PRESENTATION_SPOT
-                    : PointerControllerInterface::PRESENTATION_POINTER);
-
     // Update current gesture coordinates.
     bool cancelPreviousGesture, finishPreviousGesture;
     bool sendEvents = preparePointerGestures(when,
@@ -3487,6 +3505,15 @@
     if (!sendEvents) {
         return;
     }
+    if (finishPreviousGesture) {
+        cancelPreviousGesture = false;
+    }
+
+    // Switch pointer presentation.
+    mPointerController->setPresentation(
+            mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
+                    ? PointerControllerInterface::PRESENTATION_SPOT
+                    : PointerControllerInterface::PRESENTATION_POINTER);
 
     // Show or hide the pointer if needed.
     switch (mPointerGesture.currentGestureMode) {
@@ -3669,9 +3696,10 @@
 #endif
 
         if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
-            if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) {
+            if (when <= mPointerGesture.tapUpTime + mConfig->pointerGestureTapDragInterval) {
                 // The tap/drag timeout has not yet expired.
-                getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL);
+                getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime
+                        + mConfig->pointerGestureTapDragInterval);
             } else {
                 // The tap is finished.
 #if DEBUG_GESTURES
@@ -3683,6 +3711,8 @@
                 mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
                 mPointerGesture.currentGestureIdBits.clear();
 
+                mPointerGesture.pointerVelocityControl.reset();
+
                 if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
                     mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
                     mPointerGesture.spotIdBits.clear();
@@ -3740,7 +3770,7 @@
     if (activeTouchId < 0) {
         mPointerGesture.resetQuietTime();
     } else {
-        isQuietTime = when < mPointerGesture.quietTime + QUIET_INTERVAL;
+        isQuietTime = when < mPointerGesture.quietTime + mConfig->pointerGestureQuietInterval;
         if (!isQuietTime) {
             if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS
                     || mPointerGesture.lastGestureMode == PointerGesture::SWIPE
@@ -3777,6 +3807,8 @@
         mPointerGesture.currentGestureMode = PointerGesture::QUIET;
         mPointerGesture.currentGestureIdBits.clear();
 
+        mPointerGesture.pointerVelocityControl.reset();
+
         if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
             mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
             mPointerGesture.spotIdBits.clear();
@@ -3808,46 +3840,48 @@
 
         // Switch pointers if needed.
         // Find the fastest pointer and follow it.
-        if (activeTouchId >= 0) {
-            if (mCurrentTouch.pointerCount > 1) {
-                int32_t bestId = -1;
-                float bestSpeed = DRAG_MIN_SWITCH_SPEED;
-                for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
-                    uint32_t id = mCurrentTouch.pointers[i].id;
-                    float vx, vy;
-                    if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
-                        float speed = hypotf(vx, vy);
-                        if (speed > bestSpeed) {
-                            bestId = id;
-                            bestSpeed = speed;
-                        }
+        if (activeTouchId >= 0 && mCurrentTouch.pointerCount > 1) {
+            int32_t bestId = -1;
+            float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed;
+            for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
+                uint32_t id = mCurrentTouch.pointers[i].id;
+                float vx, vy;
+                if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
+                    float speed = hypotf(vx, vy);
+                    if (speed > bestSpeed) {
+                        bestId = id;
+                        bestSpeed = speed;
                     }
                 }
-                if (bestId >= 0 && bestId != activeTouchId) {
-                    mPointerGesture.activeTouchId = activeTouchId = bestId;
-                    activeTouchChanged = true;
+            }
+            if (bestId >= 0 && bestId != activeTouchId) {
+                mPointerGesture.activeTouchId = activeTouchId = bestId;
+                activeTouchChanged = true;
 #if DEBUG_GESTURES
-                    LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
-                            "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
+                LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
+                        "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
 #endif
-                }
             }
+        }
 
-            if (mLastTouch.idBits.hasBit(activeTouchId)) {
-                const PointerData& currentPointer =
-                        mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
-                const PointerData& lastPointer =
-                        mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
-                float deltaX = (currentPointer.x - lastPointer.x)
-                        * mLocked.pointerGestureXMovementScale;
-                float deltaY = (currentPointer.y - lastPointer.y)
-                        * mLocked.pointerGestureYMovementScale;
+        if (activeTouchId >= 0 && mLastTouch.idBits.hasBit(activeTouchId)) {
+            const PointerData& currentPointer =
+                    mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
+            const PointerData& lastPointer =
+                    mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
+            float deltaX = (currentPointer.x - lastPointer.x)
+                    * mLocked.pointerGestureXMovementScale;
+            float deltaY = (currentPointer.y - lastPointer.y)
+                    * mLocked.pointerGestureYMovementScale;
 
-                // Move the pointer using a relative motion.
-                // When using spots, the click will occur at the position of the anchor
-                // spot and all other spots will move there.
-                mPointerController->move(deltaX, deltaY);
-            }
+            mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY);
+
+            // Move the pointer using a relative motion.
+            // When using spots, the click will occur at the position of the anchor
+            // spot and all other spots will move there.
+            mPointerController->move(deltaX, deltaY);
+        } else {
+            mPointerGesture.pointerVelocityControl.reset();
         }
 
         float x, y;
@@ -3893,21 +3927,23 @@
         *outFinishPreviousGesture = true;
 
         // Watch for taps coming out of HOVER or TAP_DRAG mode.
+        // Checking for taps after TAP_DRAG allows us to detect double-taps.
         bool tapped = false;
         if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER
                 || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG)
                 && mLastTouch.pointerCount == 1) {
-            if (when <= mPointerGesture.tapDownTime + TAP_INTERVAL) {
+            if (when <= mPointerGesture.tapDownTime + mConfig->pointerGestureTapInterval) {
                 float x, y;
                 mPointerController->getPosition(&x, &y);
-                if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP
-                        && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) {
+                if (fabs(x - mPointerGesture.tapX) <= mConfig->pointerGestureTapSlop
+                        && fabs(y - mPointerGesture.tapY) <= mConfig->pointerGestureTapSlop) {
 #if DEBUG_GESTURES
                     LOGD("Gestures: TAP");
 #endif
 
                     mPointerGesture.tapUpTime = when;
-                    getContext()->requestTimeoutAtTime(when + TAP_DRAG_INTERVAL);
+                    getContext()->requestTimeoutAtTime(when
+                            + mConfig->pointerGestureTapDragInterval);
 
                     mPointerGesture.activeGestureId = 0;
                     mPointerGesture.currentGestureMode = PointerGesture::TAP;
@@ -3954,6 +3990,8 @@
             }
         }
 
+        mPointerGesture.pointerVelocityControl.reset();
+
         if (!tapped) {
 #if DEBUG_GESTURES
             LOGD("Gestures: NEUTRAL");
@@ -3977,11 +4015,11 @@
 
         mPointerGesture.currentGestureMode = PointerGesture::HOVER;
         if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
-            if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) {
+            if (when <= mPointerGesture.tapUpTime + mConfig->pointerGestureTapDragInterval) {
                 float x, y;
                 mPointerController->getPosition(&x, &y);
-                if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP
-                        && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) {
+                if (fabs(x - mPointerGesture.tapX) <= mConfig->pointerGestureTapSlop
+                        && fabs(y - mPointerGesture.tapY) <= mConfig->pointerGestureTapSlop) {
                     mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
                 } else {
 #if DEBUG_GESTURES
@@ -4010,9 +4048,13 @@
             float deltaY = (currentPointer.y - lastPointer.y)
                     * mLocked.pointerGestureYMovementScale;
 
+            mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY);
+
             // Move the pointer using a relative motion.
             // When using spots, the hover or drag will occur at the position of the anchor spot.
             mPointerController->move(deltaX, deltaY);
+        } else {
+            mPointerGesture.pointerVelocityControl.reset();
         }
 
         bool down;
@@ -4078,15 +4120,32 @@
         // a decision to transition into SWIPE or FREEFORM mode accordingly.
         LOG_ASSERT(activeTouchId >= 0);
 
-        bool needReference = false;
-        bool settled = when >= mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL;
+        bool settled = when >= mPointerGesture.firstTouchTime
+                + mConfig->pointerGestureMultitouchSettleInterval;
         if (mPointerGesture.lastGestureMode != PointerGesture::PRESS
                 && mPointerGesture.lastGestureMode != PointerGesture::SWIPE
                 && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
             *outFinishPreviousGesture = true;
+        } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) {
+            // Additional pointers have gone down but not yet settled.
+            // Reset the gesture.
+#if DEBUG_GESTURES
+            LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
+                    "settle time remaining %0.3fms",
+                    (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
+                            * 0.000001f);
+#endif
+            *outCancelPreviousGesture = true;
+        } else {
+            // Continue previous gesture.
+            mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
+        }
+
+        if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
             mPointerGesture.currentGestureMode = PointerGesture::PRESS;
             mPointerGesture.activeGestureId = 0;
             mPointerGesture.referenceIdBits.clear();
+            mPointerGesture.pointerVelocityControl.reset();
 
             if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
                     && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) {
@@ -4107,37 +4166,18 @@
                 mPointerGesture.referenceGestureX = c.getAxisValue(AMOTION_EVENT_AXIS_X);
                 mPointerGesture.referenceGestureY = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
             } else {
+                // Use the centroid and pointer location as the reference points for the gesture.
 #if DEBUG_GESTURES
                 LOGD("Gestures: Using centroid as reference for MULTITOUCH, "
                         "settle time remaining %0.3fms",
                         (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
                                 * 0.000001f);
 #endif
-                needReference = true;
+                mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
+                        &mPointerGesture.referenceTouchY);
+                mPointerController->getPosition(&mPointerGesture.referenceGestureX,
+                        &mPointerGesture.referenceGestureY);
             }
-        } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) {
-            // Additional pointers have gone down but not yet settled.
-            // Reset the gesture.
-#if DEBUG_GESTURES
-            LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
-                    "settle time remaining %0.3fms",
-                    (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
-                            * 0.000001f);
-#endif
-            *outCancelPreviousGesture = true;
-            mPointerGesture.currentGestureMode = PointerGesture::PRESS;
-            mPointerGesture.activeGestureId = 0;
-        } else {
-            // Continue previous gesture.
-            mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
-        }
-
-        if (needReference) {
-            // Use the centroid and pointer location as the reference points for the gesture.
-            mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
-                    &mPointerGesture.referenceTouchY);
-            mPointerController->getPosition(&mPointerGesture.referenceGestureX,
-                    &mPointerGesture.referenceGestureY);
         }
 
         if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
@@ -4173,14 +4213,15 @@
 
                 float speed1 = hypotf(vx1, vy1);
                 float speed2 = hypotf(vx2, vy2);
-                if (speed1 >= MULTITOUCH_MIN_SPEED && speed2 >= MULTITOUCH_MIN_SPEED) {
+                if (speed1 >= mConfig->pointerGestureMultitouchMinSpeed
+                        && speed2 >= mConfig->pointerGestureMultitouchMinSpeed) {
                     // Calculate the dot product of the velocity vectors.
                     // When the vectors are oriented in approximately the same direction,
                     // the angle betweeen them is near zero and the cosine of the angle
                     // approches 1.0.  Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
                     float dot = vx1 * vx2 + vy1 * vy2;
                     float cosine = dot / (speed1 * speed2); // denominator always > 0
-                    if (cosine >= SWIPE_TRANSITION_ANGLE_COSINE) {
+                    if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) {
                         // Pointers are moving in the same direction.  Switch to SWIPE.
 #if DEBUG_GESTURES
                         LOGD("Gestures: PRESS transitioned to SWIPE, "
@@ -4266,10 +4307,14 @@
 
                 mPointerGesture.referenceTouchX += commonDeltaX;
                 mPointerGesture.referenceTouchY += commonDeltaY;
-                mPointerGesture.referenceGestureX +=
-                        commonDeltaX * mLocked.pointerGestureXMovementScale;
-                mPointerGesture.referenceGestureY +=
-                        commonDeltaY * mLocked.pointerGestureYMovementScale;
+
+                commonDeltaX *= mLocked.pointerGestureXMovementScale;
+                commonDeltaY *= mLocked.pointerGestureYMovementScale;
+                mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
+
+                mPointerGesture.referenceGestureX += commonDeltaX;
+                mPointerGesture.referenceGestureY += commonDeltaY;
+
                 clampPositionUsingPointerBounds(mPointerController,
                         &mPointerGesture.referenceGestureX,
                         &mPointerGesture.referenceGestureY);
@@ -5376,7 +5421,8 @@
 }
 
 void MultiTouchInputMapper::clearState() {
-    mAccumulator.clear(mSlotCount);
+    mAccumulator.clearSlots(mSlotCount);
+    mAccumulator.clearButtons();
     mButtonState = 0;
 }
 
@@ -5410,13 +5456,13 @@
         }
 
         if (mAccumulator.currentSlot < 0 || size_t(mAccumulator.currentSlot) >= mSlotCount) {
-            if (newSlot) {
 #if DEBUG_POINTERS
+            if (newSlot) {
                 LOGW("MultiTouch device %s emitted invalid slot index %d but it "
                         "should be between 0 and %d; ignoring this slot.",
                         getDeviceName().string(), mAccumulator.currentSlot, mSlotCount);
-#endif
             }
+#endif
             break;
         }
 
@@ -5619,7 +5665,10 @@
 
     syncTouch(when, havePointerIds);
 
-    mAccumulator.clear(mUsingSlotsProtocol ? 0 : mSlotCount);
+    if (!mUsingSlotsProtocol) {
+        mAccumulator.clearSlots(mSlotCount);
+    }
+    mAccumulator.clearButtons();
 }
 
 void MultiTouchInputMapper::configureRawAxes() {
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 671e194..1d4ad87 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -40,6 +40,117 @@
 
 
 /*
+ * Input reader configuration.
+ *
+ * Specifies various options that modify the behavior of the input reader.
+ */
+struct InputReaderConfiguration {
+    // Determines whether to turn on some hacks we have to improve the touch interaction with a
+    // certain device whose screen currently is not all that good.
+    bool filterTouchEvents;
+
+    // Determines whether to turn on some hacks to improve touch interaction with another device
+    // where touch coordinate data can get corrupted.
+    bool filterJumpyTouchEvents;
+
+    // Gets the amount of time to disable virtual keys after the screen is touched
+    // in order to filter out accidental virtual key presses due to swiping gestures
+    // or taps near the edge of the display.  May be 0 to disable the feature.
+    nsecs_t virtualKeyQuietTime;
+
+    // The excluded device names for the platform.
+    // Devices with these names will be ignored.
+    Vector<String8> excludedDeviceNames;
+
+    // Velocity control parameters for mouse pointer movements.
+    VelocityControlParameters pointerVelocityControlParameters;
+
+    // Velocity control parameters for mouse wheel movements.
+    VelocityControlParameters wheelVelocityControlParameters;
+
+    // Quiet time between certain pointer gesture transitions.
+    // Time to allow for all fingers or buttons to settle into a stable state before
+    // starting a new gesture.
+    nsecs_t pointerGestureQuietInterval;
+
+    // The minimum speed that a pointer must travel for us to consider switching the active
+    // touch pointer to it during a drag.  This threshold is set to avoid switching due
+    // to noise from a finger resting on the touch pad (perhaps just pressing it down).
+    float pointerGestureDragMinSwitchSpeed; // in pixels per second
+
+    // Tap gesture delay time.
+    // The time between down and up must be less than this to be considered a tap.
+    nsecs_t pointerGestureTapInterval;
+
+    // Tap drag gesture delay time.
+    // The time between the previous tap's up and the next down must be less than
+    // this to be considered a drag.  Otherwise, the previous tap is finished and a
+    // new tap begins.
+    //
+    // Note that the previous tap will be held down for this entire duration so this
+    // interval must be shorter than the long press timeout.
+    nsecs_t pointerGestureTapDragInterval;
+
+    // The distance in pixels that the pointer is allowed to move from initial down
+    // to up and still be called a tap.
+    float pointerGestureTapSlop; // in pixels
+
+    // Time after the first touch points go down to settle on an initial centroid.
+    // This is intended to be enough time to handle cases where the user puts down two
+    // fingers at almost but not quite exactly the same time.
+    nsecs_t pointerGestureMultitouchSettleInterval;
+
+    // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when
+    // both of the pointers are moving at least this fast.
+    float pointerGestureMultitouchMinSpeed; // in pixels per second
+
+    // The transition from PRESS to SWIPE gesture mode can only occur when the
+    // cosine of the angle between the two vectors is greater than or equal to than this value
+    // which indicates that the vectors are oriented in the same direction.
+    // When the vectors are oriented in the exactly same direction, the cosine is 1.0.
+    // (In exactly opposite directions, the cosine is -1.0.)
+    float pointerGestureSwipeTransitionAngleCosine;
+
+    // The transition from PRESS to SWIPE gesture mode can only occur when the
+    // fingers are no more than this far apart relative to the diagonal size of
+    // the touch pad.  For example, a ratio of 0.5 means that the fingers must be
+    // no more than half the diagonal size of the touch pad apart.
+    float pointerGestureSwipeMaxWidthRatio;
+
+    // The gesture movement speed factor relative to the size of the display.
+    // Movement speed applies when the fingers are moving in the same direction.
+    // Without acceleration, a full swipe of the touch pad diagonal in movement mode
+    // will cover this portion of the display diagonal.
+    float pointerGestureMovementSpeedRatio;
+
+    // The gesture zoom speed factor relative to the size of the display.
+    // Zoom speed applies when the fingers are mostly moving relative to each other
+    // to execute a scale gesture or similar.
+    // Without acceleration, a full swipe of the touch pad diagonal in zoom mode
+    // will cover this portion of the display diagonal.
+    float pointerGestureZoomSpeedRatio;
+
+    InputReaderConfiguration() :
+            filterTouchEvents(false),
+            filterJumpyTouchEvents(false),
+            virtualKeyQuietTime(0),
+            pointerVelocityControlParameters(1.0f, 80.0f, 400.0f, 4.0f),
+            wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f),
+            pointerGestureQuietInterval(100 * 1000000LL), // 100 ms
+            pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second
+            pointerGestureTapInterval(150 * 1000000LL), // 150 ms
+            pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms
+            pointerGestureTapSlop(10.0f), // 10 pixels
+            pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms
+            pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second
+            pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees
+            pointerGestureSwipeMaxWidthRatio(0.333f),
+            pointerGestureMovementSpeedRatio(0.3f),
+            pointerGestureZoomSpeedRatio(0.3f) { }
+};
+
+
+/*
  * Input reader policy interface.
  *
  * The input reader policy is used by the input reader to interact with the Window Manager
@@ -68,24 +179,8 @@
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
-    /* Determines whether to turn on some hacks we have to improve the touch interaction with a
-     * certain device whose screen currently is not all that good.
-     */
-    virtual bool filterTouchEvents() = 0;
-
-    /* Determines whether to turn on some hacks to improve touch interaction with another device
-     * where touch coordinate data can get corrupted.
-     */
-    virtual bool filterJumpyTouchEvents() = 0;
-
-    /* Gets the amount of time to disable virtual keys after the screen is touched
-     * in order to filter out accidental virtual key presses due to swiping gestures
-     * or taps near the edge of the display.  May be 0 to disable the feature.
-     */
-    virtual nsecs_t getVirtualKeyQuietTime() = 0;
-
-    /* Gets the excluded device names for the platform. */
-    virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
+    /* Gets the input reader configuration. */
+    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0;
 
     /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0;
@@ -139,6 +234,9 @@
     /* Determine whether physical keys exist for the given framework-domain key codes. */
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
             size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
+
+    /* Reopens and reconfigures all input devices. */
+    virtual void refreshConfiguration() = 0;
 };
 
 
@@ -162,6 +260,7 @@
     virtual void requestTimeoutAtTime(nsecs_t when) = 0;
 
     virtual InputReaderPolicyInterface* getPolicy() = 0;
+    virtual const InputReaderConfiguration* getConfig() = 0;
     virtual InputDispatcherInterface* getDispatcher() = 0;
     virtual EventHubInterface* getEventHub() = 0;
 };
@@ -202,6 +301,8 @@
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
             size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
 
+    virtual void refreshConfiguration();
+
 protected:
     // These methods are protected virtual so they can be overridden and instrumented
     // by test cases.
@@ -212,7 +313,10 @@
     sp<InputReaderPolicyInterface> mPolicy;
     sp<InputDispatcherInterface> mDispatcher;
 
+    InputReaderConfiguration mConfig;
+
     virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); }
+    virtual const InputReaderConfiguration* getConfig() { return &mConfig; }
     virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); }
     virtual EventHubInterface* getEventHub() { return mEventHub.get(); }
 
@@ -240,18 +344,17 @@
     void timeoutExpired(nsecs_t when);
 
     void handleConfigurationChanged(nsecs_t when);
-    void configureExcludedDevices();
 
     // state management for all devices
     Mutex mStateLock;
 
-    int32_t mGlobalMetaState;
+    int32_t mGlobalMetaState; // guarded by mStateLock
     virtual void updateGlobalMetaState();
     virtual int32_t getGlobalMetaState();
 
     virtual void fadePointer();
 
-    InputConfiguration mInputConfiguration;
+    InputConfiguration mInputConfiguration; // guarded by mStateLock
     void updateInputConfiguration();
 
     nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread
@@ -259,9 +362,12 @@
     virtual bool shouldDropVirtualKey(nsecs_t now,
             InputDevice* device, int32_t keyCode, int32_t scanCode);
 
-    nsecs_t mNextTimeout; // only accessed by reader thread
+    nsecs_t mNextTimeout; // only accessed by reader thread, not guarded
     virtual void requestTimeoutAtTime(nsecs_t when);
 
+    volatile int32_t mRefreshConfiguration; // atomic
+    void configure(bool firstTime);
+
     // state queries
     typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
     int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
@@ -354,6 +460,7 @@
     inline const String8 getDeviceName() { return mDevice->getName(); }
     inline InputReaderContext* getContext() { return mContext; }
     inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); }
+    inline const InputReaderConfiguration* getConfig() { return mContext->getConfig(); }
     inline InputDispatcherInterface* getDispatcher() { return mContext->getDispatcher(); }
     inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
 
@@ -538,6 +645,12 @@
     float mVWheelScale;
     float mHWheelScale;
 
+    // Velocity controls for mouse pointer and wheel movements.
+    // The controls for X and Y wheel movements are separate to keep them decoupled.
+    VelocityControl mPointerVelocityControl;
+    VelocityControl mWheelXVelocityControl;
+    VelocityControl mWheelYVelocityControl;
+
     sp<PointerControllerInterface> mPointerController;
 
     struct LockedState {
@@ -669,6 +782,9 @@
     uint32_t mTouchSource; // sources when reporting touch data
     uint32_t mPointerSource; // sources when reporting pointer gestures
 
+    // The reader's configuration.
+    const InputReaderConfiguration* mConfig;
+
     // Immutable configuration parameters.
     struct Parameters {
         enum DeviceType {
@@ -684,7 +800,6 @@
         bool useBadTouchFilter;
         bool useJumpyTouchFilter;
         bool useAveragingTouchFilter;
-        nsecs_t virtualKeyQuietTime;
 
         enum GestureMode {
             GESTURE_MODE_POINTER,
@@ -964,6 +1079,8 @@
             // Exactly one finger dragging following a tap.
             // Pointer follows the active finger.
             // Emits DOWN, MOVE and UP events at the pointer location.
+            //
+            // Detect double-taps when the finger goes up while in TAP_DRAG mode.
             TAP_DRAG,
 
             // Button is pressed.
@@ -974,6 +1091,8 @@
             // Exactly one finger, button is not pressed.
             // Pointer follows the active finger.
             // Emits HOVER_MOVE events at the pointer location.
+            //
+            // Detect taps when the finger goes up while in HOVER mode.
             HOVER,
 
             // Exactly two fingers but neither have moved enough to clearly indicate
@@ -1062,6 +1181,9 @@
         // A velocity tracker for determining whether to switch active pointers during drags.
         VelocityTracker velocityTracker;
 
+        // Velocity control for pointer movements.
+        VelocityControl pointerVelocityControl;
+
         void reset() {
             firstTouchTime = LLONG_MIN;
             activeTouchId = -1;
@@ -1076,6 +1198,7 @@
             velocityTracker.clear();
             resetTap();
             resetQuietTime();
+            pointerVelocityControl.reset();
         }
 
         void resetTap() {
@@ -1243,8 +1366,7 @@
         uint32_t buttonDown;
         uint32_t buttonUp;
 
-        Accumulator() : slots(NULL) {
-            clear(false);
+        Accumulator() : currentSlot(0), slots(NULL), buttonDown(0), buttonUp(0) {
         }
 
         ~Accumulator() {
@@ -1255,11 +1377,14 @@
             slots = new Slot[slotCount];
         }
 
-        void clear(size_t slotCount) {
+        void clearSlots(size_t slotCount) {
             for (size_t i = 0; i < slotCount; i++) {
                 slots[i].clear();
             }
             currentSlot = 0;
+        }
+
+        void clearButtons() {
             buttonDown = 0;
             buttonUp = 0;
         }
diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp
index 3db3473..8dfb44b 100644
--- a/services/input/tests/InputDispatcher_test.cpp
+++ b/services/input/tests/InputDispatcher_test.cpp
@@ -35,6 +35,8 @@
 // --- FakeInputDispatcherPolicy ---
 
 class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
+    InputDispatcherConfiguration mConfig;
+
 protected:
     virtual ~FakeInputDispatcherPolicy() {
     }
@@ -55,16 +57,12 @@
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
     }
 
-    virtual nsecs_t getKeyRepeatTimeout() {
-        return 500 * 1000000LL;
+    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
+        *outConfig = mConfig;
     }
 
-    virtual nsecs_t getKeyRepeatDelay() {
-        return 50 * 1000000LL;
-    }
-
-    virtual int32_t getMaxEventsPerSecond() {
-        return 60;
+    virtual bool isKeyRepeatEnabled() {
+        return true;
     }
 
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 78d1db6..00b4222 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -120,17 +120,14 @@
     };
 
     KeyedVector<int32_t, DisplayInfo> mDisplayInfos;
-    bool mFilterTouchEvents;
-    bool mFilterJumpyTouchEvents;
-    Vector<String8> mExcludedDeviceNames;
+    InputReaderConfiguration mConfig;
     KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
 
 protected:
     virtual ~FakeInputReaderPolicy() { }
 
 public:
-    FakeInputReaderPolicy() :
-            mFilterTouchEvents(false), mFilterJumpyTouchEvents(false) {
+    FakeInputReaderPolicy() {
     }
 
     void removeDisplayInfo(int32_t displayId) {
@@ -148,11 +145,11 @@
     }
 
     void setFilterTouchEvents(bool enabled) {
-        mFilterTouchEvents = enabled;
+        mConfig.filterTouchEvents = enabled;
     }
 
     void setFilterJumpyTouchEvents(bool enabled) {
-        mFilterJumpyTouchEvents = enabled;
+        mConfig.filterJumpyTouchEvents = enabled;
     }
 
     virtual nsecs_t getVirtualKeyQuietTime() {
@@ -160,7 +157,7 @@
     }
 
     void addExcludedDeviceName(const String8& deviceName) {
-        mExcludedDeviceNames.push(deviceName);
+        mConfig.excludedDeviceNames.push(deviceName);
     }
 
     void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
@@ -187,16 +184,8 @@
         return false;
     }
 
-    virtual bool filterTouchEvents() {
-        return mFilterTouchEvents;
-    }
-
-    virtual bool filterJumpyTouchEvents() {
-        return mFilterJumpyTouchEvents;
-    }
-
-    virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
-        outExcludedDeviceNames.appendVector(mExcludedDeviceNames);
+    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) {
+        *outConfig = mConfig;
     }
 
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
@@ -640,8 +629,8 @@
         return NAME_NOT_FOUND;
     }
 
-    virtual void addExcludedDevice(const char* deviceName) {
-        mExcludedDevices.add(String8(deviceName));
+    virtual void setExcludedDevices(const Vector<String8>& devices) {
+        mExcludedDevices = devices;
     }
 
     virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
@@ -739,6 +728,9 @@
 
     virtual void dump(String8& dump) {
     }
+
+    virtual void reopenDevices() {
+    }
 };
 
 
@@ -751,6 +743,8 @@
     int32_t mGlobalMetaState;
     bool mUpdateGlobalMetaStateWasCalled;
 
+    InputReaderConfiguration mConfig;
+
 public:
     FakeInputReaderContext(const sp<EventHubInterface>& eventHub,
             const sp<InputReaderPolicyInterface>& policy,
@@ -788,6 +782,11 @@
         return mPolicy.get();
     }
 
+    virtual const InputReaderConfiguration* getConfig() {
+        mPolicy->getReaderConfiguration(&mConfig);
+        return &mConfig;
+    }
+
     virtual InputDispatcherInterface* getDispatcher() {
         return mDispatcher.get();
     }
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index c03b994..fd502d8 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -29,6 +29,7 @@
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.commons.logging.impl.SimpleLog;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 82e5e80..c2a8a1d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12398,6 +12398,15 @@
                     ac.updateConfiguration(mConfiguration);
                 }
 
+                // Make sure all resources in our process are updated
+                // right now, so that anyone who is going to retrieve
+                // resource values after we return will be sure to get
+                // the new ones.  This is especially important during
+                // boot, where the first config change needs to guarantee
+                // all resources have that config before following boot
+                // code is executed.
+                mSystemThread.applyConfigurationToResources(newConfig);
+
                 if (Settings.System.hasInterestingConfigurationChanges(changes)) {
                     Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
                     msg.obj = new Configuration(mConfiguration);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f9be46f..d8772b8 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1455,6 +1455,8 @@
                     if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
                         mService.mWindowManager.setAppStartingWindow(
                                 next, next.packageName, next.theme,
+                                mService.compatibilityInfoForPackageLocked(
+                                        next.info.applicationInfo),
                                 next.nonLocalizedLabel,
                                 next.labelRes, next.icon, next.windowFlags,
                                 null, true);
@@ -1491,6 +1493,8 @@
                 if (SHOW_APP_STARTING_PREVIEW) {
                     mService.mWindowManager.setAppStartingWindow(
                             next, next.packageName, next.theme,
+                            mService.compatibilityInfoForPackageLocked(
+                                    next.info.applicationInfo),
                             next.nonLocalizedLabel,
                             next.labelRes, next.icon, next.windowFlags,
                             null, true);
@@ -1615,7 +1619,9 @@
                     else if (prev.nowVisible) prev = null;
                 }
                 mService.mWindowManager.setAppStartingWindow(
-                        r, r.packageName, r.theme, r.nonLocalizedLabel,
+                        r, r.packageName, r.theme,
+                        mService.compatibilityInfoForPackageLocked(
+                                r.info.applicationInfo), r.nonLocalizedLabel,
                         r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
             }
         } else {
@@ -3901,10 +3907,10 @@
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
             Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
                     + Integer.toHexString(changes) + ", handles=0x"
-                    + Integer.toHexString(r.info.configChanges)
+                    + Integer.toHexString(r.info.getRealConfigChanged())
                     + ", newConfig=" + newConfig);
         }
-        if ((changes&(~r.info.configChanges)) != 0 || r.forceNewConfig) {
+        if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
             r.configChangeFlags |= changes;
             r.startFreezingScreenLocked(r.app, globalChanges);
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index 8949f48..1334bcd 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -150,9 +150,11 @@
     }
 
     public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
-        return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
+        CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
                 mService.mConfiguration.smallestScreenWidthDp,
                 (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0);
+        //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci);
+        return ci;
     }
 
     public int computeCompatModeLocked(ApplicationInfo ai) {
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 69bde41f..3095c37 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -23,10 +23,14 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.database.ContentObserver;
 import android.os.Environment;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.SystemProperties;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
 import android.util.Xml;
 import android.view.InputChannel;
@@ -57,7 +61,7 @@
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
-    
+
     private static native void nativeInit(Context context,
             Callbacks callbacks, MessageQueue messageQueue);
     private static native void nativeStart();
@@ -88,6 +92,7 @@
     private static native int[] nativeGetInputDeviceIds();
     private static native boolean nativeTransferTouchFocus(InputChannel fromChannel,
             InputChannel toChannel);
+    private static native void nativeSetPointerSpeed(int speed);
     private static native String nativeDump();
     
     // Input event injection constants defined in InputDispatcher.h.
@@ -131,10 +136,13 @@
         Slog.i(TAG, "Initializing input manager");
         nativeInit(mContext, mCallbacks, looper.getQueue());
     }
-    
+
     public void start() {
         Slog.i(TAG, "Starting input manager");
         nativeStart();
+
+        registerPointerSpeedSettingObserver();
+        updatePointerSpeedFromSettings();
     }
     
     public void setDisplaySize(int displayId, int width, int height) {
@@ -403,6 +411,42 @@
         return nativeTransferTouchFocus(fromChannel, toChannel);
     }
 
+    /**
+     * Set the pointer speed.
+     * @param speed The pointer speed as a value between -7 (slowest) and 7 (fastest)
+     * where 0 is the default speed.
+     */
+    public void setPointerSpeed(int speed) {
+        speed = Math.min(Math.max(speed, -7), 7);
+        nativeSetPointerSpeed(speed);
+    }
+
+    public void updatePointerSpeedFromSettings() {
+        int speed = getPointerSpeedSetting(0);
+        setPointerSpeed(speed);
+    }
+
+    private void registerPointerSpeedSettingObserver() {
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
+                new ContentObserver(mWindowManagerService.mH) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        updatePointerSpeedFromSettings();
+                    }
+                });
+    }
+
+    private int getPointerSpeedSetting(int defaultValue) {
+        int speed = defaultValue;
+        try {
+            speed = Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.POINTER_SPEED);
+        } catch (SettingNotFoundException snfe) {
+        }
+        return speed;
+    }
+
     public void dump(PrintWriter pw) {
         String dumpStr = nativeDump();
         if (dumpStr != null) {
@@ -573,6 +617,26 @@
         }
 
         @SuppressWarnings("unused")
+        public int getTapTimeout() {
+            return ViewConfiguration.getTapTimeout();
+        }
+
+        @SuppressWarnings("unused")
+        public int getDoubleTapTimeout() {
+            return ViewConfiguration.getDoubleTapTimeout();
+        }
+
+        @SuppressWarnings("unused")
+        public int getLongPressTimeout() {
+            return ViewConfiguration.getLongPressTimeout();
+        }
+
+        @SuppressWarnings("unused")
+        public int getTouchSlop() {
+            return ViewConfiguration.get(mContext).getScaledTouchSlop();
+        }
+
+        @SuppressWarnings("unused")
         public int getMaxEventsPerSecond() {
             int result = 0;
             try {
diff --git a/services/java/com/android/server/wm/StartingData.java b/services/java/com/android/server/wm/StartingData.java
index 625fcfe..46bb480 100644
--- a/services/java/com/android/server/wm/StartingData.java
+++ b/services/java/com/android/server/wm/StartingData.java
@@ -16,18 +16,23 @@
 
 package com.android.server.wm;
 
+import android.content.res.CompatibilityInfo;
+
 final class StartingData {
     final String pkg;
     final int theme;
+    final CompatibilityInfo compatInfo;
     final CharSequence nonLocalizedLabel;
     final int labelRes;
     final int icon;
     final int windowFlags;
 
-    StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
+    StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo,
+            CharSequence _nonLocalizedLabel,
             int _labelRes, int _icon, int _windowFlags) {
         pkg = _pkg;
         theme = _theme;
+        compatInfo = _compatInfo;
         nonLocalizedLabel = _nonLocalizedLabel;
         labelRes = _labelRes;
         icon = _icon;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 2aa53ec..d95d4c5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -602,8 +602,7 @@
 
     final Configuration mTempConfiguration = new Configuration();
 
-    // The frame use to limit the size of the app running in compatibility mode.
-    Rect mCompatibleScreenFrame = new Rect();
+    // The desired scaling factor for compatible apps.
     float mCompatibleScreenScale;
 
     public static WindowManagerService main(Context context,
@@ -3526,7 +3525,8 @@
     }
 
     public void setAppStartingWindow(IBinder token, String pkg,
-            int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
+            int theme, CompatibilityInfo compatInfo,
+            CharSequence nonLocalizedLabel, int labelRes, int icon,
             int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppStartingIcon()")) {
@@ -3676,8 +3676,7 @@
             }
 
             mStartingIconInTransition = true;
-            wtoken.startingData = new StartingData(
-                    pkg, theme, nonLocalizedLabel,
+            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
                     labelRes, icon, windowFlags);
             Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
             // Note: we really want to do sendMessageAtFrontOfQueue() because we
@@ -5566,8 +5565,7 @@
         dm.heightPixels = dm.unscaledHeightPixels = mAppDisplayHeight
                 = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
 
-        mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame(
-                dm, mCompatibleScreenFrame, null);
+        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, null);
 
         config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(mRotation, dw) / dm.density);
         config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(mRotation, dh) / dm.density);
@@ -5953,6 +5951,19 @@
         }
     }
 
+    /**
+     * Temporarily set the pointer speed.  Does not save the new setting.
+     * Used by the settings application.
+     */
+    public void setPointerSpeed(int speed) {
+        if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
+                "setPointerSpeed()")) {
+            throw new SecurityException("Requires SET_POINTER_SPEED permission");
+        }
+
+        mInputManager.setPointerSpeed(speed);
+    }
+
     private WindowState getFocusedWindow() {
         synchronized (mWindowMap) {
             return getFocusedWindowLocked();
@@ -6142,9 +6153,8 @@
                     View view = null;
                     try {
                         view = mPolicy.addStartingWindow(
-                            wtoken.token, sd.pkg,
-                            sd.theme, sd.nonLocalizedLabel, sd.labelRes,
-                            sd.icon, sd.windowFlags);
+                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
+                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
                     } catch (Exception e) {
                         Slog.w(TAG, "Exception when adding starting window", e);
                     }
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 1f10d9c..881882f1 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -53,6 +53,11 @@
 
 namespace android {
 
+// The exponent used to calculate the pointer speed scaling factor.
+// The scaling factor is calculated as 2 ^ (speed * exponent),
+// where the speed ranges from -7 to + 7 and is supplied by the user.
+static const float POINTER_SPEED_EXPONENT = 1.0f / 3;
+
 static struct {
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
@@ -71,6 +76,10 @@
     jmethodID getKeyRepeatTimeout;
     jmethodID getKeyRepeatDelay;
     jmethodID getMaxEventsPerSecond;
+    jmethodID getTapTimeout;
+    jmethodID getDoubleTapTimeout;
+    jmethodID getLongPressTimeout;
+    jmethodID getTouchSlop;
     jmethodID getPointerLayer;
     jmethodID getPointerIcon;
 } gCallbacksClassInfo;
@@ -104,6 +113,16 @@
 
 // --- Global functions ---
 
+template<typename T>
+inline static T min(const T& a, const T& b) {
+    return a < b ? a : b;
+}
+
+template<typename T>
+inline static T max(const T& a, const T& b) {
+    return a > b ? a : b;
+}
+
 static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
         const sp<InputApplicationHandle>& inputApplicationHandle) {
     if (inputApplicationHandle == NULL) {
@@ -162,15 +181,13 @@
     void setFocusedApplication(JNIEnv* env, jobject applicationObj);
     void setInputDispatchMode(bool enabled, bool frozen);
     void setSystemUiVisibility(int32_t visibility);
+    void setPointerSpeed(int32_t speed);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
-    virtual bool filterTouchEvents();
-    virtual bool filterJumpyTouchEvents();
-    virtual nsecs_t getVirtualKeyQuietTime();
-    virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
+    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
 
     /* --- InputDispatcherPolicyInterface implementation --- */
@@ -181,10 +198,9 @@
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
             const sp<InputWindowHandle>& inputWindowHandle);
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
-    virtual nsecs_t getKeyRepeatTimeout();
-    virtual nsecs_t getKeyRepeatDelay();
-    virtual int32_t getMaxEventsPerSecond();
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
+    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
+    virtual bool isKeyRepeatEnabled();
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
     virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
     virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
@@ -206,18 +222,6 @@
     jobject mCallbacksObj;
     sp<Looper> mLooper;
 
-    // Cached filtering policies.
-    int32_t mFilterTouchEvents;
-    int32_t mFilterJumpyTouchEvents;
-    nsecs_t mVirtualKeyQuietTime;
-
-    // Cached key repeat policy.
-    nsecs_t mKeyRepeatTimeout;
-    nsecs_t mKeyRepeatDelay;
-
-    // Cached throttling policy.
-    int32_t mMaxEventsPerSecond;
-
     Mutex mLock;
     struct Locked {
         // Display size information.
@@ -227,6 +231,9 @@
         // System UI visibility.
         int32_t systemUiVisibility;
 
+        // Pointer speed.
+        int32_t pointerSpeed;
+
         // Sprite controller singleton, created on first use.
         sp<SpriteController> spriteController;
 
@@ -253,10 +260,7 @@
 
 NativeInputManager::NativeInputManager(jobject contextObj,
         jobject callbacksObj, const sp<Looper>& looper) :
-        mLooper(looper),
-        mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
-        mKeyRepeatTimeout(-1), mKeyRepeatDelay(-1),
-        mMaxEventsPerSecond(-1) {
+        mLooper(looper) {
     JNIEnv* env = jniEnv();
 
     mContextObj = env->NewGlobalRef(contextObj);
@@ -269,6 +273,7 @@
         mLocked.displayOrientation = ROTATION_0;
 
         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
+        mLocked.pointerSpeed = 0;
     }
 
     sp<EventHub> eventHub = new EventHub();
@@ -369,74 +374,76 @@
     return result;
 }
 
-bool NativeInputManager::filterTouchEvents() {
-    if (mFilterTouchEvents < 0) {
-        JNIEnv* env = jniEnv();
-
-        jboolean result = env->CallBooleanMethod(mCallbacksObj,
-                gCallbacksClassInfo.filterTouchEvents);
-        if (checkAndClearExceptionFromCallback(env, "filterTouchEvents")) {
-            result = false;
-        }
-
-        mFilterTouchEvents = result ? 1 : 0;
-    }
-    return mFilterTouchEvents;
-}
-
-bool NativeInputManager::filterJumpyTouchEvents() {
-    if (mFilterJumpyTouchEvents < 0) {
-        JNIEnv* env = jniEnv();
-
-        jboolean result = env->CallBooleanMethod(mCallbacksObj,
-                gCallbacksClassInfo.filterJumpyTouchEvents);
-        if (checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) {
-            result = false;
-        }
-
-        mFilterJumpyTouchEvents = result ? 1 : 0;
-    }
-    return mFilterJumpyTouchEvents;
-}
-
-nsecs_t NativeInputManager::getVirtualKeyQuietTime() {
-    if (mVirtualKeyQuietTime < 0) {
-        JNIEnv* env = jniEnv();
-
-        jint result = env->CallIntMethod(mCallbacksObj,
-                gCallbacksClassInfo.getVirtualKeyQuietTimeMillis);
-        if (checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
-            result = 0;
-        }
-        if (result < 0) {
-            result = 0;
-        }
-
-        mVirtualKeyQuietTime = milliseconds_to_nanoseconds(result);
-    }
-    return mVirtualKeyQuietTime;
-}
-
-void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
-    outExcludedDeviceNames.clear();
-
+void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
     JNIEnv* env = jniEnv();
 
-    jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
+    jboolean filterTouchEvents = env->CallBooleanMethod(mCallbacksObj,
+            gCallbacksClassInfo.filterTouchEvents);
+    if (!checkAndClearExceptionFromCallback(env, "filterTouchEvents")) {
+        outConfig->filterTouchEvents = filterTouchEvents;
+    }
+
+    jboolean filterJumpyTouchEvents = env->CallBooleanMethod(mCallbacksObj,
+            gCallbacksClassInfo.filterJumpyTouchEvents);
+    if (!checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) {
+        outConfig->filterJumpyTouchEvents = filterJumpyTouchEvents;
+    }
+
+    jint virtualKeyQuietTime = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getVirtualKeyQuietTimeMillis);
+    if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
+        outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime);
+    }
+
+    outConfig->excludedDeviceNames.clear();
+    jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mCallbacksObj,
             gCallbacksClassInfo.getExcludedDeviceNames));
-    if (! checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && result) {
-        jsize length = env->GetArrayLength(result);
+    if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) {
+        jsize length = env->GetArrayLength(excludedDeviceNames);
         for (jsize i = 0; i < length; i++) {
-            jstring item = jstring(env->GetObjectArrayElement(result, i));
-
+            jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i));
             const char* deviceNameChars = env->GetStringUTFChars(item, NULL);
-            outExcludedDeviceNames.add(String8(deviceNameChars));
+            outConfig->excludedDeviceNames.add(String8(deviceNameChars));
             env->ReleaseStringUTFChars(item, deviceNameChars);
-
             env->DeleteLocalRef(item);
         }
-        env->DeleteLocalRef(result);
+        env->DeleteLocalRef(excludedDeviceNames);
     }
+
+    jint tapTimeout = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getTapTimeout);
+    if (!checkAndClearExceptionFromCallback(env, "getTapTimeout")) {
+        jint doubleTapTimeout = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.getDoubleTapTimeout);
+        if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
+            jint longPressTimeout = env->CallIntMethod(mCallbacksObj,
+                    gCallbacksClassInfo.getLongPressTimeout);
+            if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
+                outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(tapTimeout);
+
+                // We must ensure that the tap-drag interval is significantly shorter than
+                // the long-press timeout because the tap is held down for the entire duration
+                // of the double-tap timeout.
+                jint tapDragInterval = max(min(longPressTimeout - 100,
+                        doubleTapTimeout), tapTimeout);
+                outConfig->pointerGestureTapDragInterval =
+                        milliseconds_to_nanoseconds(tapDragInterval);
+            }
+        }
+    }
+
+    jint touchSlop = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getTouchSlop);
+    if (!checkAndClearExceptionFromCallback(env, "getTouchSlop")) {
+        outConfig->pointerGestureTapSlop = touchSlop;
+    }
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed
+                * POINTER_SPEED_EXPONENT);
+    } // release lock
 }
 
 sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) {
@@ -557,54 +564,31 @@
     }
 }
 
-nsecs_t NativeInputManager::getKeyRepeatTimeout() {
-    if (! isScreenOn()) {
-        // Disable key repeat when the screen is off.
-        return -1;
-    } else {
-        if (mKeyRepeatTimeout < 0) {
-            JNIEnv* env = jniEnv();
+void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
+    JNIEnv* env = jniEnv();
 
-            jint result = env->CallIntMethod(mCallbacksObj,
-                    gCallbacksClassInfo.getKeyRepeatTimeout);
-            if (checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
-                result = 500;
-            }
+    jint keyRepeatTimeout = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getKeyRepeatTimeout);
+    if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
+        outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
+    }
 
-            mKeyRepeatTimeout = milliseconds_to_nanoseconds(result);
-        }
-        return mKeyRepeatTimeout;
+    jint keyRepeatDelay = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getKeyRepeatDelay);
+    if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
+        outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
+    }
+
+    jint maxEventsPerSecond = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getMaxEventsPerSecond);
+    if (!checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) {
+        outConfig->maxEventsPerSecond = maxEventsPerSecond;
     }
 }
 
-nsecs_t NativeInputManager::getKeyRepeatDelay() {
-    if (mKeyRepeatDelay < 0) {
-        JNIEnv* env = jniEnv();
-
-        jint result = env->CallIntMethod(mCallbacksObj,
-                gCallbacksClassInfo.getKeyRepeatDelay);
-        if (checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
-            result = 50;
-        }
-
-        mKeyRepeatDelay = milliseconds_to_nanoseconds(result);
-    }
-    return mKeyRepeatDelay;
-}
-
-int32_t NativeInputManager::getMaxEventsPerSecond() {
-    if (mMaxEventsPerSecond < 0) {
-        JNIEnv* env = jniEnv();
-
-        jint result = env->CallIntMethod(mCallbacksObj,
-                gCallbacksClassInfo.getMaxEventsPerSecond);
-        if (checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) {
-            result = 60;
-        }
-
-        mMaxEventsPerSecond = result;
-    }
-    return mMaxEventsPerSecond;
+bool NativeInputManager::isKeyRepeatEnabled() {
+    // Only enable automatic key repeating when the screen is on.
+    return isScreenOn();
 }
 
 void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) {
@@ -665,6 +649,17 @@
             : PointerController::INACTIVITY_TIMEOUT_NORMAL);
 }
 
+void NativeInputManager::setPointerSpeed(int32_t speed) {
+    AutoMutex _l(mLock);
+
+    if (mLocked.pointerSpeed != speed) {
+        LOGI("Setting pointer speed to %d.", speed);
+        mLocked.pointerSpeed = speed;
+
+        mInputManager->getReader()->refreshConfiguration();
+    }
+}
+
 bool NativeInputManager::isScreenOn() {
     return android_server_PowerManagerService_isScreenOn();
 }
@@ -1254,6 +1249,15 @@
             transferTouchFocus(fromChannel, toChannel);
 }
 
+static void android_server_InputManager_nativeSetPointerSpeed(JNIEnv* env,
+        jclass clazz, jint speed) {
+    if (checkInputManagerUnitialized(env)) {
+        return;
+    }
+
+    gNativeInputManager->setPointerSpeed(speed);
+}
+
 static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) {
     if (checkInputManagerUnitialized(env)) {
         return NULL;
@@ -1310,6 +1314,8 @@
             (void*) android_server_InputManager_nativeGetInputConfiguration },
     { "nativeTransferTouchFocus", "(Landroid/view/InputChannel;Landroid/view/InputChannel;)Z",
             (void*) android_server_InputManager_nativeTransferTouchFocus },
+    { "nativeSetPointerSpeed", "(I)V",
+            (void*) android_server_InputManager_nativeSetPointerSpeed },
     { "nativeDump", "()Ljava/lang/String;",
             (void*) android_server_InputManager_nativeDump },
 };
@@ -1388,6 +1394,18 @@
     GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, clazz,
             "getKeyRepeatDelay", "()I");
 
+    GET_METHOD_ID(gCallbacksClassInfo.getTapTimeout, clazz,
+            "getTapTimeout", "()I");
+
+    GET_METHOD_ID(gCallbacksClassInfo.getDoubleTapTimeout, clazz,
+            "getDoubleTapTimeout", "()I");
+
+    GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, clazz,
+            "getLongPressTimeout", "()I");
+
+    GET_METHOD_ID(gCallbacksClassInfo.getTouchSlop, clazz,
+            "getTouchSlop", "()I");
+
     GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
             "getMaxEventsPerSecond", "()I");
 
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 57a3b15..ba3e6e5 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -8,7 +8,6 @@
     LinearAccelerationSensor.cpp \
     OrientationSensor.cpp \
     RotationVectorSensor.cpp \
-    SecondOrderLowPassFilter.cpp \
     SensorDevice.cpp \
     SensorFusion.cpp \
     SensorInterface.cpp \
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
index 9b75b70..1857443 100644
--- a/services/sensorservice/CorrectedGyroSensor.cpp
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -45,7 +45,7 @@
         const sensors_event_t& event)
 {
     if (event.type == SENSOR_TYPE_GYROSCOPE) {
-        const vec3_t bias(mSensorFusion.getGyroBias() * mSensorFusion.getEstimatedRate());
+        const vec3_t bias(mSensorFusion.getGyroBias());
         *outEvent = event;
         outEvent->data[0] -= bias.x;
         outEvent->data[1] -= bias.y;
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
index 56ac9f9..b5f97e0 100644
--- a/services/sensorservice/Fusion.cpp
+++ b/services/sensorservice/Fusion.cpp
@@ -24,15 +24,14 @@
 
 // -----------------------------------------------------------------------
 
-template <typename TYPE>
-static inline TYPE sqr(TYPE x) {
-    return x*x;
-}
+static const float gyroSTDEV = 3.16e-4; // rad/s^3/2
+static const float accSTDEV  = 0.05f;   // m/s^2 (measured 0.08 / CDD 0.05)
+static const float magSTDEV  = 0.5f;    // uT    (measured 0.7  / CDD 0.5)
+static const float biasSTDEV = 3.16e-5; // rad/s^1/2 (guessed)
 
-template <typename T>
-static inline T clamp(T v) {
-    return v < 0 ? 0 : v;
-}
+static const float FREE_FALL_THRESHOLD = 0.981f;
+
+// -----------------------------------------------------------------------
 
 template <typename TYPE, size_t C, size_t R>
 static mat<TYPE, R, R> scaleCovariance(
@@ -71,33 +70,6 @@
     return r;
 }
 
-template <typename TYPE>
-static mat<TYPE, 3, 3> MRPsToMatrix(const vec<TYPE, 3>& p) {
-    mat<TYPE, 3, 3> res(1);
-    const mat<TYPE, 3, 3> px(crossMatrix(p, 0));
-    const TYPE ptp(dot_product(p,p));
-    const TYPE t = 4/sqr(1+ptp);
-    res -= t * (1-ptp) * px;
-    res += t * 2 * sqr(px);
-    return res;
-}
-
-template <typename TYPE>
-vec<TYPE, 3> matrixToMRPs(const mat<TYPE, 3, 3>& R) {
-    // matrix to MRPs
-    vec<TYPE, 3> q;
-    const float Hx = R[0].x;
-    const float My = R[1].y;
-    const float Az = R[2].z;
-    const float w = 1 / (1 + sqrtf( clamp( Hx + My + Az + 1) * 0.25f ));
-    q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f ) * w;
-    q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f ) * w;
-    q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f ) * w;
-    q.x = copysignf(q.x, R[2].y - R[1].z);
-    q.y = copysignf(q.y, R[0].z - R[2].x);
-    q.z = copysignf(q.z, R[1].x - R[0].y);
-    return q;
-}
 
 template<typename TYPE, size_t SIZE>
 class Covariance {
@@ -128,11 +100,8 @@
 // -----------------------------------------------------------------------
 
 Fusion::Fusion() {
-    // process noise covariance matrix
-    const float w1 = gyroSTDEV;
-    const float w2 = biasSTDEV;
-    Q[0] = w1*w1;
-    Q[1] = w2*w2;
+    Phi[0][1] = 0;
+    Phi[1][1] = 1;
 
     Ba.x = 0;
     Ba.y = 0;
@@ -146,25 +115,46 @@
 }
 
 void Fusion::init() {
-    // initial estimate: E{ x(t0) }
-    x = 0;
-
-    // initial covariance: Var{ x(t0) }
-    P = 0;
-
     mInitState = 0;
+    mGyroRate = 0;
     mCount[0] = 0;
     mCount[1] = 0;
     mCount[2] = 0;
     mData = 0;
 }
 
+void Fusion::initFusion(const vec4_t& q, float dT)
+{
+    // initial estimate: E{ x(t0) }
+    x0 = q;
+    x1 = 0;
+
+    // process noise covariance matrix
+    //  G = | -1 0 |
+    //      |  0 1 |
+
+    const float v = gyroSTDEV;
+    const float u = biasSTDEV;
+    const float q00 = v*v*dT + 0.33333f*(dT*dT*dT)*u*u;
+    const float q10 =              0.5f*(dT*dT)   *u*u;
+    const float q01 = q10;
+    const float q11 = u*u*dT;
+    GQGt[0][0] =  q00;
+    GQGt[1][0] = -q10;
+    GQGt[0][1] = -q01;
+    GQGt[1][1] =  q11;
+
+
+    // initial covariance: Var{ x(t0) }
+    P = 0;
+}
+
 bool Fusion::hasEstimate() const {
     return (mInitState == (MAG|ACC|GYRO));
 }
 
-bool Fusion::checkInitComplete(int what, const vec3_t& d) {
-    if (mInitState == (MAG|ACC|GYRO))
+bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) {
+    if (hasEstimate())
         return true;
 
     if (what == ACC) {
@@ -176,7 +166,8 @@
         mCount[1]++;
         mInitState |= MAG;
     } else if (what == GYRO) {
-        mData[2] += d;
+        mGyroRate = dT;
+        mData[2] += d*dT;
         mCount[2]++;
         if (mCount[2] == 64) {
             // 64 samples is good enough to estimate the gyro drift and
@@ -199,37 +190,29 @@
         east *= 1/length(east);
         vec3_t north(cross_product(up, east));
         R << east << north << up;
-        x[0] = matrixToMRPs(R);
+        const vec4_t q = matrixToQuat(R);
 
-        // NOTE: we could try to use the average of the gyro data
-        // to estimate the initial bias, but this only works if
-        // the device is not moving. For now, we don't use that value
-        // and start with a bias of 0.
-        x[1] = 0;
-
-        // initial covariance
-        P = 0;
+        initFusion(q, mGyroRate);
     }
 
     return false;
 }
 
 void Fusion::handleGyro(const vec3_t& w, float dT) {
-    const vec3_t wdT(w * dT);   // rad/s * s -> rad
-    if (!checkInitComplete(GYRO, wdT))
+    if (!checkInitComplete(GYRO, w, dT))
         return;
 
-    predict(wdT);
+    predict(w, dT);
 }
 
 status_t Fusion::handleAcc(const vec3_t& a) {
-    if (length(a) < 0.981f)
+    // ignore acceleration data if we're close to free-fall
+    if (length(a) < FREE_FALL_THRESHOLD)
         return BAD_VALUE;
 
     if (!checkInitComplete(ACC, a))
         return BAD_VALUE;
 
-    // ignore acceleration data if we're close to free-fall
     const float l = 1/length(a);
     update(a*l, Ba, accSTDEV*l);
     return NO_ERROR;
@@ -251,20 +234,6 @@
     const float l = 1 / length(north);
     north *= l;
 
-#if 0
-    // in practice the magnetic-field sensor is so wrong
-    // that there is no point trying to use it to constantly
-    // correct the gyro. instead, we use the mag-sensor only when
-    // the device points north (just to give us a reference).
-    // We're hoping that it'll actually point north, if it doesn't
-    // we'll be offset, but at least the instantaneous posture
-    // of the device will be correct.
-
-    const float cos_30 = 0.8660254f;
-    if (dot_product(north, Bm) < cos_30)
-        return BAD_VALUE;
-#endif
-
     update(north, Bm, magSTDEV*l);
     return NO_ERROR;
 }
@@ -273,7 +242,7 @@
     if (isnanf(length(v))) {
         LOGW("9-axis fusion diverged. reseting state.");
         P = 0;
-        x[1] = 0;
+        x1 = 0;
         mInitState = 0;
         mCount[0] = 0;
         mCount[1] = 0;
@@ -284,145 +253,89 @@
     return true;
 }
 
-vec3_t Fusion::getAttitude() const {
-    return x[0];
+vec4_t Fusion::getAttitude() const {
+    return x0;
 }
 
 vec3_t Fusion::getBias() const {
-    return x[1];
+    return x1;
 }
 
 mat33_t Fusion::getRotationMatrix() const {
-    return MRPsToMatrix(x[0]);
+    return quatToMatrix(x0);
 }
 
-mat33_t Fusion::getF(const vec3_t& p) {
-    const float p0 = p.x;
-    const float p1 = p.y;
-    const float p2 = p.z;
-
-    // f(p, w)
-    const float p0p1 = p0*p1;
-    const float p0p2 = p0*p2;
-    const float p1p2 = p1*p2;
-    const float p0p0 = p0*p0;
-    const float p1p1 = p1*p1;
-    const float p2p2 = p2*p2;
-    const float pp = 0.5f * (1 - (p0p0 + p1p1 + p2p2));
-
-    mat33_t F;
-    F[0][0] = 0.5f*(p0p0 + pp);
-    F[0][1] = 0.5f*(p0p1 + p2);
-    F[0][2] = 0.5f*(p0p2 - p1);
-    F[1][0] = 0.5f*(p0p1 - p2);
-    F[1][1] = 0.5f*(p1p1 + pp);
-    F[1][2] = 0.5f*(p1p2 + p0);
-    F[2][0] = 0.5f*(p0p2 + p1);
-    F[2][1] = 0.5f*(p1p2 - p0);
-    F[2][2] = 0.5f*(p2p2 + pp);
+mat34_t Fusion::getF(const vec4_t& q) {
+    mat34_t F;
+    F[0].x = q.w;   F[1].x =-q.z;   F[2].x = q.y;
+    F[0].y = q.z;   F[1].y = q.w;   F[2].y =-q.x;
+    F[0].z =-q.y;   F[1].z = q.x;   F[2].z = q.w;
+    F[0].w =-q.x;   F[1].w =-q.y;   F[2].w =-q.z;
     return F;
 }
 
-mat33_t Fusion::getdFdp(const vec3_t& p, const vec3_t& we) {
+void Fusion::predict(const vec3_t& w, float dT) {
+    const vec4_t q  = x0;
+    const vec3_t b  = x1;
+    const vec3_t we = w - b;
+    const vec4_t dq = getF(q)*((0.5f*dT)*we);
+    x0 = normalize_quat(q + dq);
 
-    // dF = | A = df/dp  -F |
-    //      |   0         0 |
+    // P(k+1) = F*P(k)*Ft + G*Q*Gt
 
-    mat33_t A;
-    A[0][0] = A[1][1] = A[2][2] = 0.5f * (p.x*we.x + p.y*we.y + p.z*we.z);
-    A[0][1] = 0.5f * (p.y*we.x - p.x*we.y - we.z);
-    A[0][2] = 0.5f * (p.z*we.x - p.x*we.z + we.y);
-    A[1][2] = 0.5f * (p.z*we.y - p.y*we.z - we.x);
-    A[1][0] = -A[0][1];
-    A[2][0] = -A[0][2];
-    A[2][1] = -A[1][2];
-    return A;
-}
+    //  Phi = | Phi00 Phi10 |
+    //        |   0     1   |
+    const mat33_t I33(1);
+    const mat33_t I33dT(dT);
+    const mat33_t wx(crossMatrix(we, 0));
+    const mat33_t wx2(wx*wx);
+    const float lwedT = length(we)*dT;
+    const float ilwe = 1/length(we);
+    const float k0 = (1-cosf(lwedT))*(ilwe*ilwe);
+    const float k1 = sinf(lwedT);
 
-void Fusion::predict(const vec3_t& w) {
-    // f(p, w)
-    vec3_t& p(x[0]);
+    Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0;
+    Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
 
-    // There is a discontinuity at 2.pi, to avoid it we need to switch to
-    // the shadow of p when pT.p gets too big.
-    const float ptp(dot_product(p,p));
-    if (ptp >= 2.0f) {
-        p = -p * (1/ptp);
-    }
-
-    const mat33_t F(getF(p));
-
-    // compute w with the bias correction:
-    //  w_estimated = w - b_estimated
-    const vec3_t& b(x[1]);
-    const vec3_t we(w - b);
-
-    // prediction
-    const vec3_t dX(F*we);
-
-    if (!checkState(dX))
-        return;
-
-    p += dX;
-
-    const mat33_t A(getdFdp(p, we));
-
-    // G  = | G0  0 |  =  | -F  0 |
-    //      |  0  1 |     |  0  1 |
-
-    // P += A*P + P*At + F*Q*Ft
-    const mat33_t AP(A*transpose(P[0][0]));
-    const mat33_t PAt(P[0][0]*transpose(A));
-    const mat33_t FPSt(F*transpose(P[1][0]));
-    const mat33_t PSFt(P[1][0]*transpose(F));
-    const mat33_t FQFt(scaleCovariance(F, Q[0]));
-    P[0][0] += AP + PAt - FPSt - PSFt + FQFt;
-    P[1][0] += A*P[1][0] - F*P[1][1];
-    P[1][1] += Q[1];
+    P = Phi*P*transpose(Phi) + GQGt;
 }
 
 void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) {
-    const vec3_t p(x[0]);
+    vec4_t q(x0);
     // measured vector in body space: h(p) = A(p)*Bi
-    const mat33_t A(MRPsToMatrix(p));
+    const mat33_t A(quatToMatrix(q));
     const vec3_t Bb(A*Bi);
 
     // Sensitivity matrix H = dh(p)/dp
     // H = [ L 0 ]
-    const float ptp(dot_product(p,p));
-    const mat33_t px(crossMatrix(p, 0.5f*(ptp-1)));
-    const mat33_t ppt(p*transpose(p));
-    const mat33_t L((8 / sqr(1+ptp))*crossMatrix(Bb, 0)*(ppt-px));
+    const mat33_t L(crossMatrix(Bb, 0));
 
-    // update...
+    // gain...
+    // K = P*Ht / [H*P*Ht + R]
+    vec<mat33_t, 2> K;
     const mat33_t R(sigma*sigma);
     const mat33_t S(scaleCovariance(L, P[0][0]) + R);
     const mat33_t Si(invert(S));
     const mat33_t LtSi(transpose(L)*Si);
-
-    vec<mat33_t, 2> K;
     K[0] = P[0][0] * LtSi;
     K[1] = transpose(P[1][0])*LtSi;
 
-    const vec3_t e(z - Bb);
-    const vec3_t K0e(K[0]*e);
-    const vec3_t K1e(K[1]*e);
-
-    if (!checkState(K0e))
-        return;
-
-    if (!checkState(K1e))
-        return;
-
-    x[0] += K0e;
-    x[1] += K1e;
-
+    // update...
     // P -= K*H*P;
     const mat33_t K0L(K[0] * L);
     const mat33_t K1L(K[1] * L);
     P[0][0] -= K0L*P[0][0];
     P[1][1] -= K1L*P[1][0];
     P[1][0] -= K0L*P[1][0];
+    P[0][1] = transpose(P[1][0]);
+
+    const vec3_t e(z - Bb);
+    const vec3_t dq(K[0]*e);
+    const vec3_t db(K[1]*e);
+
+    q += getF(q)*(0.5f*dq);
+    x0 = normalize_quat(q);
+    x1 += db;
 }
 
 // -----------------------------------------------------------------------
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
index 571a415..556944b 100644
--- a/services/sensorservice/Fusion.h
+++ b/services/sensorservice/Fusion.h
@@ -19,42 +19,39 @@
 
 #include <utils/Errors.h>
 
-#include "vec.h"
+#include "quat.h"
 #include "mat.h"
+#include "vec.h"
 
 namespace android {
 
+typedef mat<float, 3, 4> mat34_t;
+
 class Fusion {
     /*
      * the state vector is made of two sub-vector containing respectively:
      * - modified Rodrigues parameters
      * - the estimated gyro bias
      */
-    vec<vec3_t, 2> x;
+    quat_t  x0;
+    vec3_t  x1;
 
     /*
      * the predicated covariance matrix is made of 4 3x3 sub-matrices and it
      * semi-definite positive.
      *
      * P = | P00  P10 | = | P00  P10 |
-     *     | P01  P11 |   | P10t  Q1 |
+     *     | P01  P11 |   | P10t P11 |
      *
      * Since P01 = transpose(P10), the code below never calculates or
-     * stores P01. P11 is always equal to Q1, so we don't store it either.
+     * stores P01.
      */
     mat<mat33_t, 2, 2> P;
 
     /*
-     * the process noise covariance matrix is made of 2 3x3 sub-matrices
-     * Q0 encodes the attitude's noise
-     * Q1 encodes the bias' noise
+     * the process noise covariance matrix
      */
-    vec<mat33_t, 2> Q;
-
-    static const float gyroSTDEV = 1.0e-5;  // rad/s (measured 1.2e-5)
-    static const float accSTDEV  = 0.05f;   // m/s^2 (measured 0.08 / CDD 0.05)
-    static const float magSTDEV  = 0.5f;    // uT    (measured 0.7  / CDD 0.5)
-    static const float biasSTDEV = 2e-9;    // rad/s^2 (guessed)
+    mat<mat33_t, 2, 2> GQGt;
 
 public:
     Fusion();
@@ -62,23 +59,25 @@
     void handleGyro(const vec3_t& w, float dT);
     status_t handleAcc(const vec3_t& a);
     status_t handleMag(const vec3_t& m);
-    vec3_t getAttitude() const;
+    vec4_t getAttitude() const;
     vec3_t getBias() const;
     mat33_t getRotationMatrix() const;
     bool hasEstimate() const;
 
 private:
+    mat<mat33_t, 2, 2> Phi;
     vec3_t Ba, Bm;
     uint32_t mInitState;
+    float mGyroRate;
     vec<vec3_t, 3> mData;
     size_t mCount[3];
     enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
-    bool checkInitComplete(int, const vec3_t&);
+    bool checkInitComplete(int, const vec3_t& w, float d = 0);
+    void initFusion(const vec4_t& q0, float dT);
     bool checkState(const vec3_t& v);
-    void predict(const vec3_t& w);
+    void predict(const vec3_t& w, float dT);
     void update(const vec3_t& z, const vec3_t& Bi, float sigma);
-    static mat33_t getF(const vec3_t& p);
-    static mat33_t getdFdp(const vec3_t& p, const vec3_t& we);
+    static mat34_t getF(const vec4_t& p);
 };
 
 }; // namespace android
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 541fad2..c57715f 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -31,10 +31,7 @@
 
 GravitySensor::GravitySensor(sensor_t const* list, size_t count)
     : mSensorDevice(SensorDevice::getInstance()),
-      mSensorFusion(SensorFusion::getInstance()),
-      mAccTime(0),
-      mLowPass(M_SQRT1_2, 1.5f),
-      mX(mLowPass), mY(mLowPass), mZ(mLowPass)
+      mSensorFusion(SensorFusion::getInstance())
 {
     for (size_t i=0 ; i<count ; i++) {
         if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
@@ -50,30 +47,14 @@
     const static double NS2S = 1.0 / 1000000000.0;
     if (event.type == SENSOR_TYPE_ACCELEROMETER) {
         vec3_t g;
-        if (mSensorFusion.hasGyro()) {
-            if (!mSensorFusion.hasEstimate())
-                return false;
-            const mat33_t R(mSensorFusion.getRotationMatrix());
-            // FIXME: we need to estimate the length of gravity because
-            // the accelerometer may have a small scaling error. This
-            // translates to an offset in the linear-acceleration sensor.
-            g = R[2] * GRAVITY_EARTH;
-        } else {
-            const double now = event.timestamp * NS2S;
-            if (mAccTime == 0) {
-                g.x = mX.init(event.acceleration.x);
-                g.y = mY.init(event.acceleration.y);
-                g.z = mZ.init(event.acceleration.z);
-            } else {
-                double dT = now - mAccTime;
-                mLowPass.setSamplingPeriod(dT);
-                g.x = mX(event.acceleration.x);
-                g.y = mY(event.acceleration.y);
-                g.z = mZ(event.acceleration.z);
-            }
-            g *= (GRAVITY_EARTH / length(g));
-            mAccTime = now;
-        }
+        if (!mSensorFusion.hasEstimate())
+            return false;
+        const mat33_t R(mSensorFusion.getRotationMatrix());
+        // FIXME: we need to estimate the length of gravity because
+        // the accelerometer may have a small scaling error. This
+        // translates to an offset in the linear-acceleration sensor.
+        g = R[2] * GRAVITY_EARTH;
+
         *outEvent = event;
         outEvent->data[0] = g.x;
         outEvent->data[1] = g.y;
@@ -86,42 +67,24 @@
 }
 
 status_t GravitySensor::activate(void* ident, bool enabled) {
-    status_t err;
-    if (mSensorFusion.hasGyro()) {
-        err = mSensorFusion.activate(this, enabled);
-    } else {
-        err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled);
-        if (err == NO_ERROR) {
-            if (enabled) {
-                mAccTime = 0;
-            }
-        }
-    }
-    return err;
+    return mSensorFusion.activate(this, enabled);
 }
 
-status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns)
-{
-    if (mSensorFusion.hasGyro()) {
-        return mSensorFusion.setDelay(this, ns);
-    } else {
-        return mSensorDevice.setDelay(this, mAccelerometer.getHandle(), ns);
-    }
+status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) {
+    return mSensorFusion.setDelay(this, ns);
 }
 
 Sensor GravitySensor::getSensor() const {
     sensor_t hwSensor;
     hwSensor.name       = "Gravity Sensor";
     hwSensor.vendor     = "Google Inc.";
-    hwSensor.version    = mSensorFusion.hasGyro() ? 3 : 2;
+    hwSensor.version    = 3;
     hwSensor.handle     = '_grv';
     hwSensor.type       = SENSOR_TYPE_GRAVITY;
     hwSensor.maxRange   = GRAVITY_EARTH * 2;
     hwSensor.resolution = mAccelerometer.getResolution();
-    hwSensor.power      = mSensorFusion.hasGyro() ?
-            mSensorFusion.getPowerUsage() : mAccelerometer.getPowerUsage();
-    hwSensor.minDelay   = mSensorFusion.hasGyro() ?
-            mSensorFusion.getMinDelay() : mAccelerometer.getMinDelay();
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mSensorFusion.getMinDelay();
     Sensor sensor(&hwSensor);
     return sensor;
 }
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
index 0ca3a3c..ac177c4 100644
--- a/services/sensorservice/GravitySensor.h
+++ b/services/sensorservice/GravitySensor.h
@@ -23,7 +23,6 @@
 #include <gui/Sensor.h>
 
 #include "SensorInterface.h"
-#include "SecondOrderLowPassFilter.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -36,10 +35,6 @@
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
     Sensor mAccelerometer;
-    double mAccTime;
-
-    SecondOrderLowPassFilter mLowPass;
-    CascadedBiquadFilter<float> mX, mY, mZ;
 
 public:
     GravitySensor(sensor_t const* list, size_t count);
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
index c9e5080..037adaa 100644
--- a/services/sensorservice/OrientationSensor.cpp
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -50,9 +50,10 @@
                 g[0] += 360;
 
             *outEvent = event;
-            outEvent->data[0] = g.x;
-            outEvent->data[1] = g.y;
-            outEvent->data[2] = g.z;
+            outEvent->orientation.azimuth = g.x;
+            outEvent->orientation.pitch   = g.y;
+            outEvent->orientation.roll    = g.z;
+            outEvent->orientation.status  = SENSOR_STATUS_ACCURACY_HIGH;
             outEvent->sensor = '_ypr';
             outEvent->type = SENSOR_TYPE_ORIENTATION;
             return true;
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index cba89c9..5ea9568 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -27,11 +27,6 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-template <typename T>
-static inline T clamp(T v) {
-    return v < 0 ? 0 : v;
-}
-
 RotationVectorSensor::RotationVectorSensor()
     : mSensorDevice(SensorDevice::getInstance()),
       mSensorFusion(SensorFusion::getInstance())
@@ -43,29 +38,12 @@
 {
     if (event.type == SENSOR_TYPE_ACCELEROMETER) {
         if (mSensorFusion.hasEstimate()) {
-            const mat33_t R(mSensorFusion.getRotationMatrix());
-
-            // matrix to rotation vector (normalized quaternion)
-            const float Hx = R[0].x;
-            const float My = R[1].y;
-            const float Az = R[2].z;
-
-            float qw = sqrtf( clamp( Hx + My + Az + 1) * 0.25f );
-            float qx = sqrtf( clamp( Hx - My - Az + 1) * 0.25f );
-            float qy = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f );
-            float qz = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f );
-            qx = copysignf(qx, R[2].y - R[1].z);
-            qy = copysignf(qy, R[0].z - R[2].x);
-            qz = copysignf(qz, R[1].x - R[0].y);
-
-            // this quaternion is guaranteed to be normalized, by construction
-            // of the rotation matrix.
-
+            const vec4_t q(mSensorFusion.getAttitude());
             *outEvent = event;
-            outEvent->data[0] = qx;
-            outEvent->data[1] = qy;
-            outEvent->data[2] = qz;
-            outEvent->data[3] = qw;
+            outEvent->data[0] = q.x;
+            outEvent->data[1] = q.y;
+            outEvent->data[2] = q.z;
+            outEvent->data[3] = q.w;
             outEvent->sensor = '_rov';
             outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
             return true;
@@ -86,7 +64,7 @@
     sensor_t hwSensor;
     hwSensor.name       = "Rotation Vector Sensor";
     hwSensor.vendor     = "Google Inc.";
-    hwSensor.version    = mSensorFusion.hasGyro() ? 3 : 2;
+    hwSensor.version    = 3;
     hwSensor.handle     = '_rov';
     hwSensor.type       = SENSOR_TYPE_ROTATION_VECTOR;
     hwSensor.maxRange   = 1;
@@ -98,5 +76,54 @@
 }
 
 // ---------------------------------------------------------------------------
+
+GyroDriftSensor::GyroDriftSensor()
+    : mSensorDevice(SensorDevice::getInstance()),
+      mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool GyroDriftSensor::process(sensors_event_t* outEvent,
+        const sensors_event_t& event)
+{
+    if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+        if (mSensorFusion.hasEstimate()) {
+            const vec3_t b(mSensorFusion.getGyroBias());
+            *outEvent = event;
+            outEvent->data[0] = b.x;
+            outEvent->data[1] = b.y;
+            outEvent->data[2] = b.z;
+            outEvent->sensor = '_gbs';
+            outEvent->type = SENSOR_TYPE_ACCELEROMETER;
+            return true;
+        }
+    }
+    return false;
+}
+
+status_t GyroDriftSensor::activate(void* ident, bool enabled) {
+    return mSensorFusion.activate(this, enabled);
+}
+
+status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) {
+    return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor GyroDriftSensor::getSensor() const {
+    sensor_t hwSensor;
+    hwSensor.name       = "Gyroscope Bias (debug)";
+    hwSensor.vendor     = "Google Inc.";
+    hwSensor.version    = 1;
+    hwSensor.handle     = '_gbs';
+    hwSensor.type       = SENSOR_TYPE_ACCELEROMETER;
+    hwSensor.maxRange   = 1;
+    hwSensor.resolution = 1.0f / (1<<24);
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mSensorFusion.getMinDelay();
+    Sensor sensor(&hwSensor);
+    return sensor;
+}
+
+// ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index ac76487..bb97fe1 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -24,7 +24,6 @@
 
 #include "SensorDevice.h"
 #include "SensorInterface.h"
-#include "SecondOrderLowPassFilter.h"
 
 #include "Fusion.h"
 #include "SensorFusion.h"
@@ -47,6 +46,20 @@
     virtual bool isVirtual() const { return true; }
 };
 
+class GyroDriftSensor : public SensorInterface {
+    SensorDevice& mSensorDevice;
+    SensorFusion& mSensorFusion;
+
+public:
+    GyroDriftSensor();
+    virtual bool process(sensors_event_t* outEvent,
+            const sensors_event_t& event);
+    virtual status_t activate(void* ident, bool enabled);
+    virtual status_t setDelay(void* ident, int handle, int64_t ns);
+    virtual Sensor getSensor() const;
+    virtual bool isVirtual() const { return true; }
+};
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/sensorservice/SecondOrderLowPassFilter.cpp b/services/sensorservice/SecondOrderLowPassFilter.cpp
deleted file mode 100644
index c76dd4c..0000000
--- a/services/sensorservice/SecondOrderLowPassFilter.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <math.h>
-
-#include <cutils/log.h>
-
-#include "SecondOrderLowPassFilter.h"
-#include "vec.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-SecondOrderLowPassFilter::SecondOrderLowPassFilter(float Q, float fc)
-    : iQ(1.0f / Q), fc(fc)
-{
-}
-
-void SecondOrderLowPassFilter::setSamplingPeriod(float dT)
-{
-    K = tanf(float(M_PI) * fc * dT);
-    iD = 1.0f / (K*K + K*iQ + 1);
-    a0 = K*K*iD;
-    a1 = 2.0f * a0;
-    b1 = 2.0f*(K*K - 1)*iD;
-    b2 = (K*K - K*iQ + 1)*iD;
-}
-
-// ---------------------------------------------------------------------------
-
-template<typename T>
-BiquadFilter<T>::BiquadFilter(const SecondOrderLowPassFilter& s)
-    : s(s)
-{
-}
-
-template<typename T>
-T BiquadFilter<T>::init(const T& x)
-{
-    x1 = x2 = x;
-    y1 = y2 = x;
-    return x;
-}
-
-template<typename T>
-T BiquadFilter<T>::operator()(const T& x)
-{
-    T y = (x + x2)*s.a0 + x1*s.a1 - y1*s.b1 - y2*s.b2;
-    x2 = x1;
-    y2 = y1;
-    x1 = x;
-    y1 = y;
-    return y;
-}
-
-// ---------------------------------------------------------------------------
-
-template<typename T>
-CascadedBiquadFilter<T>::CascadedBiquadFilter(const SecondOrderLowPassFilter& s)
-    : mA(s), mB(s)
-{
-}
-
-template<typename T>
-T CascadedBiquadFilter<T>::init(const T& x)
-{
-    mA.init(x);
-    mB.init(x);
-    return x;
-}
-
-template<typename T>
-T CascadedBiquadFilter<T>::operator()(const T& x)
-{
-    return mB(mA(x));
-}
-
-// ---------------------------------------------------------------------------
-
-template class BiquadFilter<float>;
-template class CascadedBiquadFilter<float>;
-template class BiquadFilter<vec3_t>;
-template class CascadedBiquadFilter<vec3_t>;
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/sensorservice/SecondOrderLowPassFilter.h b/services/sensorservice/SecondOrderLowPassFilter.h
deleted file mode 100644
index 0cc2446..0000000
--- a/services/sensorservice/SecondOrderLowPassFilter.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef ANDROID_SECOND_ORDER_LOW_PASS_FILTER_H
-#define ANDROID_SECOND_ORDER_LOW_PASS_FILTER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-template<typename T>
-class BiquadFilter;
-
-/*
- * State of a 2nd order low-pass IIR filter
- */
-class SecondOrderLowPassFilter {
-    template<typename T>
-    friend class BiquadFilter;
-    float iQ, fc;
-    float K, iD;
-    float a0, a1;
-    float b1, b2;
-public:
-    SecondOrderLowPassFilter(float Q, float fc);
-    void setSamplingPeriod(float dT);
-};
-
-/*
- * Implements a Biquad IIR filter
- */
-template<typename T>
-class BiquadFilter {
-    T x1, x2;
-    T y1, y2;
-    const SecondOrderLowPassFilter& s;
-public:
-    BiquadFilter(const SecondOrderLowPassFilter& s);
-    T init(const T& in);
-    T operator()(const T& in);
-};
-
-/*
- * Two cascaded biquad IIR filters
- * (4-poles IIR)
- */
-template<typename T>
-class CascadedBiquadFilter {
-    BiquadFilter<T> mA;
-    BiquadFilter<T> mB;
-public:
-    CascadedBiquadFilter(const SecondOrderLowPassFilter& s);
-    T init(const T& in);
-    T operator()(const T& in);
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SECOND_ORDER_LOW_PASS_FILTER_H
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index d4226ec..4ec0c8c 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -25,9 +25,7 @@
 
 SensorFusion::SensorFusion()
     : mSensorDevice(SensorDevice::getInstance()),
-      mEnabled(false), mHasGyro(false), mGyroTime(0), mRotationMatrix(1),
-      mLowPass(M_SQRT1_2, 1.0f), mAccData(mLowPass),
-      mFilteredMag(0.0f), mFilteredAcc(0.0f)
+      mEnabled(false), mGyroTime(0)
 {
     sensor_t const* list;
     size_t count = mSensorDevice.getSensorList(&list);
@@ -42,55 +40,32 @@
             mGyro = Sensor(list + i);
             // 200 Hz for gyro events is a good compromise between precision
             // and power/cpu usage.
-            mTargetDelayNs = 1000000000LL/200;
-            mGyroRate = 1000000000.0f / mTargetDelayNs;
-            mHasGyro = true;
+            mGyroRate = 200;
+            mTargetDelayNs = 1000000000LL/mGyroRate;
         }
     }
     mFusion.init();
-    mAccData.init(vec3_t(0.0f));
 }
 
 void SensorFusion::process(const sensors_event_t& event) {
-
-    if (event.type == SENSOR_TYPE_GYROSCOPE && mHasGyro) {
+    if (event.type == SENSOR_TYPE_GYROSCOPE) {
         if (mGyroTime != 0) {
             const float dT = (event.timestamp - mGyroTime) / 1000000000.0f;
             const float freq = 1 / dT;
-            const float alpha = 2 / (2 + dT); // 2s time-constant
-            mGyroRate = mGyroRate*alpha +  freq*(1 - alpha);
+            if (freq >= 100 && freq<1000) { // filter values obviously wrong
+                const float alpha = 1 / (1 + dT); // 1s time-constant
+                mGyroRate = freq + (mGyroRate - freq)*alpha;
+            }
         }
         mGyroTime = event.timestamp;
         mFusion.handleGyro(vec3_t(event.data), 1.0f/mGyroRate);
     } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
         const vec3_t mag(event.data);
-        if (mHasGyro) {
-            mFusion.handleMag(mag);
-        } else {
-            const float l(length(mag));
-            if (l>5 && l<100) {
-                mFilteredMag = mag * (1/l);
-            }
-        }
+        mFusion.handleMag(mag);
     } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
         const vec3_t acc(event.data);
-        if (mHasGyro) {
-            mFusion.handleAcc(acc);
-            mRotationMatrix = mFusion.getRotationMatrix();
-        } else {
-            const float l(length(acc));
-            if (l > 0.981f) {
-                // remove the linear-acceleration components
-                mFilteredAcc = mAccData(acc * (1/l));
-            }
-            if (length(mFilteredAcc)>0 && length(mFilteredMag)>0) {
-                vec3_t up(mFilteredAcc);
-                vec3_t east(cross_product(mFilteredMag, up));
-                east *= 1/length(east);
-                vec3_t north(cross_product(up, east));
-                mRotationMatrix << east << north << up;
-            }
-        }
+        mFusion.handleAcc(acc);
+        mAttitude = mFusion.getAttitude();
     }
 }
 
@@ -116,40 +91,31 @@
 
     mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
     mSensorDevice.activate(ident, mMag.getHandle(), enabled);
-    if (mHasGyro) {
-        mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
-    }
+    mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
 
     const bool newState = mClients.size() != 0;
     if (newState != mEnabled) {
         mEnabled = newState;
         if (newState) {
             mFusion.init();
+            mGyroTime = 0;
         }
     }
     return NO_ERROR;
 }
 
 status_t SensorFusion::setDelay(void* ident, int64_t ns) {
-    if (mHasGyro) {
-        mSensorDevice.setDelay(ident, mAcc.getHandle(), ns);
-        mSensorDevice.setDelay(ident, mMag.getHandle(), ms2ns(20));
-        mSensorDevice.setDelay(ident, mGyro.getHandle(), mTargetDelayNs);
-    } else {
-        const static double NS2S = 1.0 / 1000000000.0;
-        mSensorDevice.setDelay(ident, mAcc.getHandle(), ns);
-        mSensorDevice.setDelay(ident, mMag.getHandle(), max(ns, mMag.getMinDelayNs()));
-        mLowPass.setSamplingPeriod(ns*NS2S);
-    }
+    mSensorDevice.setDelay(ident, mAcc.getHandle(), ns);
+    mSensorDevice.setDelay(ident, mMag.getHandle(), ms2ns(20));
+    mSensorDevice.setDelay(ident, mGyro.getHandle(), mTargetDelayNs);
     return NO_ERROR;
 }
 
 
 float SensorFusion::getPowerUsage() const {
-    float power = mAcc.getPowerUsage() + mMag.getPowerUsage();
-    if (mHasGyro) {
-        power += mGyro.getPowerUsage();
-    }
+    float power =   mAcc.getPowerUsage() +
+                    mMag.getPowerUsage() +
+                    mGyro.getPowerUsage();
     return power;
 }
 
@@ -159,17 +125,17 @@
 
 void SensorFusion::dump(String8& result, char* buffer, size_t SIZE) {
     const Fusion& fusion(mFusion);
-    snprintf(buffer, SIZE, "Fusion (%s) %s (%d clients), gyro-rate=%7.2fHz, "
-            "MRPS=< %g, %g, %g > (%g), "
-            "BIAS=< %g, %g, %g >\n",
-            mHasGyro ? "9-axis" : "6-axis",
+    snprintf(buffer, SIZE, "9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, "
+            "q=< %g, %g, %g, %g > (%g), "
+            "b=< %g, %g, %g >\n",
             mEnabled ? "enabled" : "disabled",
             mClients.size(),
             mGyroRate,
             fusion.getAttitude().x,
             fusion.getAttitude().y,
             fusion.getAttitude().z,
-            dot_product(fusion.getAttitude(), fusion.getAttitude()),
+            fusion.getAttitude().w,
+            length(fusion.getAttitude()),
             fusion.getBias().x,
             fusion.getBias().y,
             fusion.getBias().z);
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
index c7eab12..4c99bcb 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -27,7 +27,6 @@
 #include <gui/Sensor.h>
 
 #include "Fusion.h"
-#include "SecondOrderLowPassFilter.h"
 
 // ---------------------------------------------------------------------------
 
@@ -45,15 +44,10 @@
     Sensor mGyro;
     Fusion mFusion;
     bool mEnabled;
-    bool mHasGyro;
     float mGyroRate;
     nsecs_t mTargetDelayNs;
     nsecs_t mGyroTime;
-    mat33_t mRotationMatrix;
-    SecondOrderLowPassFilter mLowPass;
-    BiquadFilter<vec3_t> mAccData;
-    vec3_t mFilteredMag;
-    vec3_t mFilteredAcc;
+    vec4_t mAttitude;
     SortedVector<void*> mClients;
 
     SensorFusion();
@@ -62,9 +56,9 @@
     void process(const sensors_event_t& event);
 
     bool isEnabled() const { return mEnabled; }
-    bool hasGyro() const { return mHasGyro; }
-    bool hasEstimate() const { return !mHasGyro || mFusion.hasEstimate(); }
-    mat33_t getRotationMatrix() const { return mRotationMatrix; }
+    bool hasEstimate() const { return mFusion.hasEstimate(); }
+    mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); }
+    vec4_t getAttitude() const { return mAttitude; }
     vec3_t getGyroBias() const { return mFusion.getBias(); }
     float getEstimatedRate() const { return mGyroRate; }
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 5b86d10..d1b10f7 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -18,6 +18,8 @@
 #include <math.h>
 #include <sys/types.h>
 
+#include <cutils/properties.h>
+
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
@@ -46,6 +48,16 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+/*
+ * Notes:
+ *
+ * - what about a gyro-corrected magnetic-field sensor?
+ * - option to "hide" the HAL sensors
+ * - run mag sensor from time to time to force calibration
+ * - gravity sensor length is wrong (=> drift in linear-acc sensor)
+ *
+ */
+
 SensorService::SensorService()
     : mDump("android.permission.DUMP"),
       mInitCheck(NO_INIT)
@@ -59,6 +71,7 @@
     SensorDevice& dev(SensorDevice::getInstance());
 
     if (dev.initCheck() == NO_ERROR) {
+        bool hasGyro = false;
         uint32_t virtualSensorsNeeds =
                 (1<<SENSOR_TYPE_GRAVITY) |
                 (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
@@ -69,6 +82,9 @@
         for (int i=0 ; i<count ; i++) {
             registerSensor( new HardwareSensor(list[i]) );
             switch (list[i].type) {
+                case SENSOR_TYPE_GYROSCOPE:
+                    hasGyro = true;
+                    break;
                 case SENSOR_TYPE_GRAVITY:
                 case SENSOR_TYPE_LINEAR_ACCELERATION:
                 case SENSOR_TYPE_ROTATION_VECTOR:
@@ -82,21 +98,26 @@
         // registered)
         const SensorFusion& fusion(SensorFusion::getInstance());
 
-        // Always instantiate Android's virtual sensors. Since they are
-        // instantiated behind sensors from the HAL, they won't
-        // interfere with applications, unless they looks specifically
-        // for them (by name).
+        if (hasGyro) {
+            // Always instantiate Android's virtual sensors. Since they are
+            // instantiated behind sensors from the HAL, they won't
+            // interfere with applications, unless they looks specifically
+            // for them (by name).
 
-        registerVirtualSensor( new RotationVectorSensor() );
-        registerVirtualSensor( new GravitySensor(list, count) );
-        registerVirtualSensor( new LinearAccelerationSensor(list, count) );
+            registerVirtualSensor( new RotationVectorSensor() );
+            registerVirtualSensor( new GravitySensor(list, count) );
+            registerVirtualSensor( new LinearAccelerationSensor(list, count) );
 
-        // if we have a gyro, we have the option of enabling these
-        // "better" orientation and gyro sensors
-        if (fusion.hasGyro()) {
-            // FIXME: OrientationSensor buggy when not pointing north
+            // these are optional
             registerVirtualSensor( new OrientationSensor() );
             registerVirtualSensor( new CorrectedGyroSensor(list, count) );
+
+            // virtual debugging sensors...
+            char value[PROPERTY_VALUE_MAX];
+            property_get("debug.sensors", value, "0");
+            if (atoi(value)) {
+                registerVirtualSensor( new GyroDriftSensor() );
+            }
         }
 
         run("SensorService", PRIORITY_URGENT_DISPLAY);
diff --git a/services/sensorservice/quat.h b/services/sensorservice/quat.h
new file mode 100644
index 0000000..fea1afe
--- /dev/null
+++ b/services/sensorservice/quat.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_QUAT_H
+#define ANDROID_QUAT_H
+
+#include <math.h>
+
+#include "vec.h"
+#include "mat.h"
+
+// -----------------------------------------------------------------------
+namespace android {
+// -----------------------------------------------------------------------
+
+template <typename TYPE>
+mat<TYPE, 3, 3> quatToMatrix(const vec<TYPE, 4>& q) {
+    mat<TYPE, 3, 3> R;
+    TYPE q0(q.w);
+    TYPE q1(q.x);
+    TYPE q2(q.y);
+    TYPE q3(q.z);
+    TYPE sq_q1 = 2 * q1 * q1;
+    TYPE sq_q2 = 2 * q2 * q2;
+    TYPE sq_q3 = 2 * q3 * q3;
+    TYPE q1_q2 = 2 * q1 * q2;
+    TYPE q3_q0 = 2 * q3 * q0;
+    TYPE q1_q3 = 2 * q1 * q3;
+    TYPE q2_q0 = 2 * q2 * q0;
+    TYPE q2_q3 = 2 * q2 * q3;
+    TYPE q1_q0 = 2 * q1 * q0;
+    R[0][0] = 1 - sq_q2 - sq_q3;
+    R[0][1] = q1_q2 - q3_q0;
+    R[0][2] = q1_q3 + q2_q0;
+    R[1][0] = q1_q2 + q3_q0;
+    R[1][1] = 1 - sq_q1 - sq_q3;
+    R[1][2] = q2_q3 - q1_q0;
+    R[2][0] = q1_q3 - q2_q0;
+    R[2][1] = q2_q3 + q1_q0;
+    R[2][2] = 1 - sq_q1 - sq_q2;
+    return R;
+}
+
+template <typename TYPE>
+vec<TYPE, 4> matrixToQuat(const mat<TYPE, 3, 3>& R) {
+    // matrix to quaternion
+
+    struct {
+        inline TYPE operator()(TYPE v) {
+            return v < 0 ? 0 : v;
+        }
+    } clamp;
+
+    vec<TYPE, 4> q;
+    const float Hx = R[0].x;
+    const float My = R[1].y;
+    const float Az = R[2].z;
+    q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f );
+    q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f );
+    q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f );
+    q.w = sqrtf( clamp( Hx + My + Az + 1) * 0.25f );
+    q.x = copysignf(q.x, R[2].y - R[1].z);
+    q.y = copysignf(q.y, R[0].z - R[2].x);
+    q.z = copysignf(q.z, R[1].x - R[0].y);
+    // guaranteed to be unit-quaternion
+    return q;
+}
+
+template <typename TYPE>
+vec<TYPE, 4> normalize_quat(const vec<TYPE, 4>& q) {
+    vec<TYPE, 4> r(q);
+    if (r.w < 0) {
+        r = -r;
+    }
+    return normalize(r);
+}
+
+// -----------------------------------------------------------------------
+
+typedef vec4_t quat_t;
+
+// -----------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_QUAT_H */
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index 736ff37..f74ccc5 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -208,6 +208,15 @@
 }
 
 template <
+    template<typename T, size_t S> class V,
+    typename TYPE,
+    size_t SIZE
+>
+V<TYPE, SIZE> PURE normalize(const V<TYPE, SIZE>& v) {
+    return v * (1/length(v));
+}
+
+template <
     template<typename T, size_t S> class VLHS,
     template<typename T, size_t S> class VRHS,
     typename TYPE
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index ba05837..fce7cdc 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -387,62 +387,77 @@
                 && mIsEmergencyOnly == s.mIsEmergencyOnly);
     }
 
+    /**
+     * Convert radio technology to String
+     *
+     * @param radioTechnology
+     * @return String representation of the RAT
+     *
+     * @hide
+     */
+    public static String radioTechnologyToString(int rt) {
+        String rtString;
+
+        switch(rt) {
+            case 0:
+                rtString = "Unknown";
+                break;
+            case 1:
+                rtString = "GPRS";
+                break;
+            case 2:
+                rtString = "EDGE";
+                break;
+            case 3:
+                rtString = "UMTS";
+                break;
+            case 4:
+                rtString = "CDMA-IS95A";
+                break;
+            case 5:
+                rtString = "CDMA-IS95B";
+                break;
+            case 6:
+                rtString = "1xRTT";
+                break;
+            case 7:
+                rtString = "EvDo-rev.0";
+                break;
+            case 8:
+                rtString = "EvDo-rev.A";
+                break;
+            case 9:
+                rtString = "HSDPA";
+                break;
+            case 10:
+                rtString = "HSUPA";
+                break;
+            case 11:
+                rtString = "HSPA";
+                break;
+            case 12:
+                rtString = "EvDo-rev.B";
+                break;
+            case 13:
+                rtString = "eHRPD";
+                break;
+            case 14:
+                rtString = "LTE";
+                break;
+            case 15:
+                rtString = "HSPAP";
+                break;
+            default:
+                rtString = "Unexpected";
+                Log.w(LOG_TAG, "Unexpected radioTechnology=" + rt);
+                break;
+        }
+        return rtString + ":" + rt;
+    }
+
     @Override
     public String toString() {
-        String radioTechnology = new String("Error in radioTechnology");
-        switch(this.mRadioTechnology) {
-        case 0:
-            radioTechnology = "Unknown";
-            break;
-        case 1:
-            radioTechnology = "GPRS";
-            break;
-        case 2:
-            radioTechnology = "EDGE";
-            break;
-        case 3:
-            radioTechnology = "UMTS";
-            break;
-        case 4:
-            radioTechnology = "IS95A";
-            break;
-        case 5:
-            radioTechnology = "IS95B";
-            break;
-        case 6:
-            radioTechnology = "1xRTT";
-            break;
-        case 7:
-            radioTechnology = "EvDo rev. 0";
-            break;
-        case 8:
-            radioTechnology = "EvDo rev. A";
-            break;
-        case 9:
-            radioTechnology = "HSDPA";
-            break;
-        case 10:
-            radioTechnology = "HSUPA";
-            break;
-        case 11:
-            radioTechnology = "HSPA";
-            break;
-        case 12:
-            radioTechnology = "EvDo rev. B";
-            break;
-        case 13:
-            radioTechnology = "eHRPD";
-            break;
-        case 14:
-            radioTechnology = "LTE";
-            break;
-        case 15:
-            radioTechnology = "HSPAP";
-            break;
-        default:
-            Log.w(LOG_TAG, "mRadioTechnology variable out of range.");
-        break;
-        }
+        String radioTechnology = radioTechnologyToString(mRadioTechnology);
 
         return (mState + " " + (mRoaming ? "roaming" : "home")
                 + " " + mOperatorAlphaLong
@@ -551,7 +566,7 @@
      *
      * @hide
      */
-    public void setCdmaEriText(String longName) {
+    public void setOperatorAlphaLong(String longName) {
         mOperatorAlphaLong = longName;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index da233cc..19441cd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -145,6 +145,15 @@
     boolean supplyPin(String pin);
 
     /**
+     * Supply puk to unlock the SIM and set SIM pin to new pin.
+     *  Blocks until a result is determined.
+     * @param puk The puk to check.
+     *        pin The new pin to be set in SIM
+     * @return whether the operation was a success.
+     */
+    boolean supplyPuk(String puk, String pin);
+
+    /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
      * without SEND (so <code>dial</code> is not appropriate).
      *
@@ -254,7 +263,7 @@
       * Returns the network type
       */
     int getNetworkType();
-    
+
     /**
      * Return true if an ICC card is present
      */
diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java
index b40f945..cafc79b 100644
--- a/telephony/java/com/android/internal/telephony/IccConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccConstants.java
@@ -58,6 +58,12 @@
     static final int EF_CST = 0x6f32;
     static final int EF_RUIM_SPN =0x6F41;
 
+    // ETSI TS.102.221
+    static final int EF_PL = 0x2F05;
+    // 3GPP2 C.S0065
+    static final int EF_CSIM_LI = 0x6F3A;
+    static final int EF_CSIM_SPN =0x6F41;
+
     //ISIM access
     static final int EF_IMPU = 0x6f04;
     static final int EF_IMPI = 0x6f02;
diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java
index 92ddd2c..93b9b79 100644
--- a/telephony/java/com/android/internal/telephony/IccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java
@@ -529,6 +529,7 @@
             return MF_SIM + DF_TELECOM;
 
         case EF_ICCID:
+        case EF_PL:
             return MF_SIM;
         case EF_IMG:
             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 2f22d74..45562ca 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -24,6 +24,7 @@
 import android.os.ServiceManager;
 
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * SimPhoneBookInterfaceManager to provide an inter-process communication to
@@ -63,14 +64,14 @@
                                     " total " + recordSize[1] +
                                     " #record " + recordSize[2]);
                         }
-                        mLock.notifyAll();
+                        notifyPending(ar);
                     }
                     break;
                 case EVENT_UPDATE_DONE:
                     ar = (AsyncResult) msg.obj;
                     synchronized (mLock) {
                         success = (ar.exception == null);
-                        mLock.notifyAll();
+                        notifyPending(ar);
                     }
                     break;
                 case EVENT_LOAD_DONE:
@@ -84,11 +85,20 @@
                                 records.clear();
                             }
                         }
-                        mLock.notifyAll();
+                        notifyPending(ar);
                     }
                     break;
             }
         }
+
+        private void notifyPending(AsyncResult ar) {
+            if (ar.userObj == null) {
+                return;
+            }
+            AtomicBoolean status = (AtomicBoolean) ar.userObj;
+            status.set(true);
+            mLock.notifyAll();
+        }
     };
 
     public IccPhoneBookInterfaceManager(PhoneBase phone) {
@@ -150,15 +160,12 @@
         synchronized(mLock) {
             checkThread();
             success = false;
-            Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE);
+            AtomicBoolean status = new AtomicBoolean(false);
+            Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE, status);
             AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber);
             AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
             adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response);
-            try {
-                mLock.wait();
-            } catch (InterruptedException e) {
-                logd("interrupted while trying to update by search");
-            }
+            waitForResult(status);
         }
         return success;
     }
@@ -197,14 +204,11 @@
         synchronized(mLock) {
             checkThread();
             success = false;
-            Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE);
+            AtomicBoolean status = new AtomicBoolean(false);
+            Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE, status);
             AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
             adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response);
-            try {
-                mLock.wait();
-            } catch (InterruptedException e) {
-                logd("interrupted while trying to update by index");
-            }
+            waitForResult(status);
         }
         return success;
     }
@@ -243,15 +247,12 @@
 
         synchronized(mLock) {
             checkThread();
-            Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
+            AtomicBoolean status = new AtomicBoolean(false);
+            Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE, status);
             adnCache.requestLoadAllAdnLike(efid, adnCache.extensionEfForEf(efid), response);
-            try {
-                mLock.wait();
-            } catch (InterruptedException e) {
-                logd("interrupted while trying to load from the SIM");
-            }
+            waitForResult(status);
         }
-            return records;
+        return records;
     }
 
     protected void checkThread() {
@@ -265,6 +266,16 @@
         }
     }
 
+    protected void waitForResult(AtomicBoolean status) {
+        while (!status.get()) {
+            try {
+                mLock.wait();
+            } catch (InterruptedException e) {
+                logd("interrupted while trying to update by search");
+            }
+        }
+    }
+
     private int updateEfForIccType(int efid) {
         // Check if we are trying to read ADN records
         if (efid == IccConstants.EF_ADN) {
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 695805c..01b807d 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -54,6 +54,12 @@
     protected boolean mDesiredPowerState;
 
     /**
+     *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ definitions.
+     */
+    protected int mRadioTechnology = 0;
+    protected int mNewRadioTechnology = 0;
+
+    /**
      * By default, strength polling is enabled.  However, if we're
      * getting unsolicited signal strength updates from the radio, set
      * value to true and don't bother polling any more.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 586e6b3..fe2fcb2 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -58,8 +58,9 @@
     @Override
     protected void initSstIcc() {
         mSST = new CdmaLteServiceStateTracker(this);
-        mIccRecords = new SIMRecords(this);
+        mIccRecords = new CdmaLteUiccRecords(this);
         mIccCard = new SimCard(this, LOG_TAG, DBG);
+        mIccFileHandler = new CdmaLteUiccFileHandler(this);
     }
 
     @Override
@@ -87,7 +88,7 @@
             // already been called
 
             ret = DataState.DISCONNECTED;
-        } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
+        } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
             // If we're out of service, open TCP sockets may still work
             // but no data will flow
             ret = DataState.DISCONNECTED;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 4fa369c3..a283062 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -156,13 +156,13 @@
         mSST = new CdmaServiceStateTracker(this);
         mIccRecords = new RuimRecords(this);
         mIccCard = new RuimCard(this, LOG_TAG, DBG);
+        mIccFileHandler = new RuimFileHandler(this);
     }
 
     protected void init(Context context, PhoneNotifier notifier) {
         mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
         mCT = new CdmaCallTracker(this);
         mSMS = new CdmaSMSDispatcher(this);
-        mIccFileHandler = new RuimFileHandler(this);
         mDataConnectionTracker = new CdmaDataConnectionTracker (this);
         mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
         mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
@@ -337,7 +337,7 @@
     public DataActivityState getDataActivityState() {
         DataActivityState ret = DataActivityState.NONE;
 
-        if (mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
+        if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
 
             switch (mDataConnectionTracker.getActivity()) {
                 case DATAIN:
@@ -618,7 +618,7 @@
              // already been called
 
              ret = DataState.DISCONNECTED;
-        } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
+        } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
             // If we're out of service, open TCP sockets may still work
             // but no data will flow
             ret = DataState.DISCONNECTED;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index e3e3d78..8ce221a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -175,7 +175,7 @@
 
     @Override
     protected boolean isDataAllowed() {
-        int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState();
+        int psState = mCdmaPhone.mSST.getCurrentDataConnectionState();
         boolean roaming = (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled());
         boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
 
@@ -258,7 +258,7 @@
             return true;
         }
 
-        int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState();
+        int psState = mCdmaPhone.mSST.getCurrentDataConnectionState();
         boolean roaming = mPhone.getServiceState().getRoaming();
         boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index e593bd0..7bc7ca2 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -32,6 +32,7 @@
 import android.os.RegistrantList;
 import android.os.AsyncResult;
 import android.os.Message;
+import android.os.SystemProperties;
 
 import android.util.Log;
 import android.util.EventLog;
@@ -72,6 +73,7 @@
             handlePollStateResult(msg.what, ar);
             break;
         case EVENT_SIM_READY:
+            if (DBG) log("handleMessage EVENT_SIM_READY");
             isSubscriptionFromRuim = false;
             cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
             pollState();
@@ -186,39 +188,6 @@
         }
     }
 
-    protected static String networkTypeToString(int type) {
-        String ret = "unknown";
-
-        switch (type) {
-            case ServiceState.RADIO_TECHNOLOGY_IS95A:
-            case ServiceState.RADIO_TECHNOLOGY_IS95B:
-                ret = "CDMA";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_1xRTT:
-                ret = "CDMA - 1xRTT";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
-                ret = "CDMA - EvDo rev. 0";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
-                ret = "CDMA - EvDo rev. A";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_EVDO_B:
-                ret = "CDMA - EvDo rev. B";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_LTE:
-                ret = "LTE";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_EHRPD:
-                ret = "CDMA - eHRPD";
-                break;
-            default:
-                sloge("networkTypeToString: Wrong network, can not return a string.");
-                break;
-        }
-        return ret;
-    }
-
     @Override
     protected void pollStateDone() {
         // determine data NetworkType from both LET and CDMA SS
@@ -282,13 +251,20 @@
              (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A));
 
         if (DBG) {
-            log("pollStateDone: hasRegistered = "
-                + hasRegistered + " hasCdmaDataConnectionAttached = "
-                + hasCdmaDataConnectionAttached + " hasCdmaDataConnectionChanged = "
-                + hasCdmaDataConnectionChanged + " hasNetworkTypeChanged = "
-                + hasNetworkTypeChanged + " has4gHandoff = " + has4gHandoff
-                + " hasMultiApnSupport = " + hasMultiApnSupport + " hasLostMultiApnSupport = "
-                + hasLostMultiApnSupport);
+            log("pollStateDone:"
+                + " hasRegistered=" + hasRegistered
+                + " hasDeegistered=" + hasDeregistered
+                + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
+                + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
+                + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
+                + " hasNetworkTypeChanged = " + hasNetworkTypeChanged
+                + " hasChanged=" + hasChanged
+                + " hasRoamingOn=" + hasRoamingOn
+                + " hasRoamingOff=" + hasRoamingOff
+                + " hasLocationChanged=" + hasLocationChanged
+                + " has4gHandoff = " + has4gHandoff
+                + " hasMultiApnSupport=" + hasMultiApnSupport
+                + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
         }
         // Add an event log when connection state changes
         if (ss.getState() != newSS.getState()
@@ -316,7 +292,7 @@
                 && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) {
             if (DBG)log("GsmDataConnectionTracker disposed");
             phone.mDataConnectionTracker.dispose();
-            phone.mDataConnectionTracker = new CdmaDataConnectionTracker((CDMAPhone)phone);
+            phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone);
         }
 
         CdmaCellLocation tcl = cellLoc;
@@ -330,7 +306,7 @@
 
         if (hasNetworkTypeChanged) {
             phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                    networkTypeToString(networkType));
+                    ServiceState.radioTechnologyToString(networkType));
         }
 
         if (hasRegistered) {
@@ -351,7 +327,14 @@
                     eriText = phone.getContext()
                             .getText(com.android.internal.R.string.roamingTextSearching).toString();
                 }
-                ss.setCdmaEriText(eriText);
+                ss.setOperatorAlphaLong(eriText);
+            }
+            if (cm.getSimState().isSIMReady()) {
+                // SIM is found on the device. Read the operator name from the card.
+                ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
+
+                // If SIM card is present, Eri will not be used. Turn it off
+                ss.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_OFF);
             }
 
             String operatorNumeric;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
new file mode 100644
index 0000000..2aede29
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
@@ -0,0 +1,52 @@
+/*
+ * 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.telephony.cdma;
+
+import android.util.Log;
+import com.android.internal.telephony.IccConstants;
+import com.android.internal.telephony.IccFileHandler;
+
+/**
+ * {@hide}
+ */
+public final class CdmaLteUiccFileHandler extends IccFileHandler {
+    static final String LOG_TAG = "CDMA";
+
+    CdmaLteUiccFileHandler(CDMALTEPhone phone) {
+        super(phone);
+    }
+
+    protected String getEFPath(int efid) {
+        switch(efid) {
+        case EF_CSIM_SPN:
+        case EF_CSIM_LI:
+            return MF_SIM + DF_CDMA;
+        case EF_AD:
+            return MF_SIM + DF_GSM;
+        }
+        return getCommonIccEFPath(efid);
+    }
+
+    protected void logd(String msg) {
+        Log.d(LOG_TAG, "[CdmaLteUiccFileHandler] " + msg);
+    }
+
+    protected void loge(String msg) {
+        Log.e(LOG_TAG, "[CdmaLteUiccFileHandler] " + msg);
+    }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
new file mode 100755
index 0000000..78879d6
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -0,0 +1,215 @@
+/*
+ * 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.telephony.cdma;
+
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.gsm.SIMRecords;
+import android.os.AsyncResult;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.util.Log;
+
+
+/**
+ * {@hide}
+ */
+public final class CdmaLteUiccRecords extends SIMRecords {
+    // From CSIM application
+    private byte[] mEFpl = null;
+    private byte[] mEFli = null;
+    boolean csimSpnDisplayCondition = false;
+
+    private static final int EVENT_GET_PL_DONE = CSIM_EVENT_BASE;
+    private static final int EVENT_GET_CSIM_LI_DONE = CSIM_EVENT_BASE + 1;
+    private static final int EVENT_GET_CSIM_SPN_DONE = CSIM_EVENT_BASE + 2;
+
+    public CdmaLteUiccRecords(PhoneBase p) {
+        super(p);
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        AsyncResult ar;
+        byte data[];
+
+        boolean isCsimRecordLoadResponse = false;
+
+        try { switch (msg.what) {
+            case EVENT_GET_PL_DONE:
+                // Refer to ETSI TS.102.221
+                if (DBG) log("EF_GET_EF_PL_DONE");
+                isCsimRecordLoadResponse = true;
+
+                ar = (AsyncResult) msg.obj;
+
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception = " + ar.exception);
+                    break;
+                }
+
+                mEFpl = (byte[]) ar.result;
+                if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEFpl));
+                break;
+
+            case EVENT_GET_CSIM_LI_DONE:
+                // Refer to C.S0065 5.2.26
+                if (DBG) log("EVENT_GET_CSIM_LI_DONE");
+                isCsimRecordLoadResponse = true;
+
+                ar = (AsyncResult) msg.obj;
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception = " + ar.exception);
+                    break;
+                }
+
+                mEFli = (byte[]) ar.result;
+                // convert csim efli data to iso 639 format
+                for (int i = 0; i < mEFli.length; i+=2) {
+                    switch(mEFli[i+1]) {
+                    case 0x01: mEFli[i] = 'e'; mEFli[i+1] = 'n';break;
+                    case 0x02: mEFli[i] = 'f'; mEFli[i+1] = 'r';break;
+                    case 0x03: mEFli[i] = 'e'; mEFli[i+1] = 's';break;
+                    case 0x04: mEFli[i] = 'j'; mEFli[i+1] = 'a';break;
+                    case 0x05: mEFli[i] = 'k'; mEFli[i+1] = 'o';break;
+                    case 0x06: mEFli[i] = 'z'; mEFli[i+1] = 'h';break;
+                    case 0x07: mEFli[i] = 'h'; mEFli[i+1] = 'e';break;
+                    default: mEFli[i] = ' '; mEFli[i+1] = ' ';
+                    }
+                }
+
+                if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEFli));
+                break;
+            case EVENT_GET_CSIM_SPN_DONE:
+                // Refer to C.S0065 5.2.32
+                if (DBG) log("EVENT_GET_CSIM_SPN_DONE");
+                isCsimRecordLoadResponse = true;
+                ar = (AsyncResult) msg.obj;
+
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception=" + ar.exception);
+                    break;
+                }
+                onGetCSimSpnDone(ar);
+                break;
+            default:
+                super.handleMessage(msg);
+        }}catch (RuntimeException exc) {
+            Log.w(LOG_TAG, "Exception parsing SIM record", exc);
+        } finally {
+            if (isCsimRecordLoadResponse) {
+                onRecordLoaded();
+            }
+        }
+    }
+
+    @Override
+    protected void onRecordLoaded() {
+        // One record loaded successfully or failed, In either case
+        // we need to update the recordsToLoad count
+        recordsToLoad -= 1;
+
+        if (recordsToLoad == 0 && recordsRequested == true) {
+            onAllRecordsLoaded();
+        } else if (recordsToLoad < 0) {
+            Log.e(LOG_TAG, "SIMRecords: recordsToLoad <0, programmer error suspected");
+            recordsToLoad = 0;
+        }
+    }
+
+    @Override
+    protected void fetchSimRecords() {
+        IccFileHandler iccFh = phone.getIccFileHandler();
+        recordsRequested = true;
+
+        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_PL, obtainMessage(EVENT_GET_PL_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_CSIM_LI, obtainMessage(EVENT_GET_CSIM_LI_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_CSIM_SPN, obtainMessage(EVENT_GET_CSIM_SPN_DONE));
+        recordsToLoad++;
+    }
+
+    private void onGetCSimSpnDone(AsyncResult ar) {
+        byte[] data = (byte[]) ar.result;
+        if (DBG) log("CSIM_SPN=" +
+                     IccUtils.bytesToHexString(data));
+
+        // C.S0065 for EF_SPN decoding
+        csimSpnDisplayCondition = ((0x02 & data[0]) > 0)?true:false;
+
+        int encoding = data[1];
+        int language = data[2];
+        byte[] spnData = new byte[32];
+        System.arraycopy(data, 3, spnData, 0, (data.length < 32)?data.length:32);
+
+        int numBytes;
+        for (numBytes = 0; numBytes < spnData.length; numBytes++) {
+            if ((spnData[numBytes] & 0xFF) == 0xFF) break;
+        }
+
+        if (numBytes == 0) {
+            spn = "";
+            return;
+        }
+        try {
+            switch (encoding) {
+            case UserData.ENCODING_OCTET:
+            case UserData.ENCODING_LATIN:
+                spn = new String(spnData, 0, numBytes, "ISO-8859-1");
+                break;
+            case UserData.ENCODING_IA5:
+            case UserData.ENCODING_GSM_7BIT_ALPHABET:
+            case UserData.ENCODING_7BIT_ASCII:
+                spn = GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7);
+                break;
+            case UserData.ENCODING_UNICODE_16:
+                spn =  new String(spnData, 0, numBytes, "utf-16");
+                break;
+            default:
+                log("SPN encoding not supported");
+            }
+        } catch(Exception e) {
+            log("spn decode error: " + e);
+        }
+        if (DBG) log("spn=" + spn);
+        if (DBG) log("spnCondition=" + csimSpnDisplayCondition);
+        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+    }
+
+    public byte[] getPreferredLanguage() {
+        return mEFpl;
+    }
+
+    public byte[] getLanguageIndication() {
+        return mEFli;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 0fd0614..ead6bca 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -253,6 +253,7 @@
 
         switch (msg.what) {
         case EVENT_RADIO_AVAILABLE:
+            if (DBG) log("handleMessage: EVENT_RADIO_AVAILABLE");
             break;
 
         case EVENT_RUIM_READY:
@@ -266,7 +267,7 @@
             }
 
             cm.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
-            if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
+            if (DBG) log("handleMessage: EVENT_RUIM_READY, Send Request getCDMASubscription.");
 
             // Restore the previous network selection.
             pollState();
@@ -280,6 +281,7 @@
             // For Non-RUIM phones, the subscription information is stored in
             // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
             // subscription info.
+            if (DBG) log("handleMessage: EVENT_NV_READY, Send Request getCDMASubscription.");
             cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
             pollState();
             // Signal strength polling stops when radio is off.
@@ -871,36 +873,6 @@
         }
     }
 
-    protected static String networkTypeToString(int type) {
-        String ret = "unknown";
-
-        switch (type) {
-        case ServiceState.RADIO_TECHNOLOGY_IS95A:
-        case ServiceState.RADIO_TECHNOLOGY_IS95B:
-            ret = "CDMA";
-            break;
-        case ServiceState.RADIO_TECHNOLOGY_1xRTT:
-            ret = "CDMA - 1xRTT";
-            break;
-        case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
-            ret = "CDMA - EvDo rev. 0";
-            break;
-        case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
-            ret = "CDMA - EvDo rev. A";
-            break;
-        case ServiceState.RADIO_TECHNOLOGY_EVDO_B:
-            ret = "CDMA - EvDo rev. B";
-            break;
-        default:
-            if (DBG) {
-                slog("Wrong network. Can not return a string.");
-            }
-        break;
-        }
-
-        return ret;
-    }
-
     protected void fixTimeZone(String isoCountryCode) {
         TimeZone zone = null;
         // If the offset is (0, false) and the time zone property
@@ -998,7 +970,7 @@
 
         if (hasNetworkTypeChanged) {
             phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                    networkTypeToString(networkType));
+                    ServiceState.radioTechnologyToString(networkType));
         }
 
         if (hasRegistered) {
@@ -1017,7 +989,7 @@
                     eriText = phone.getContext().getText(
                             com.android.internal.R.string.roamingTextSearching).toString();
                 }
-                ss.setCdmaEriText(eriText);
+                ss.setOperatorAlphaLong(eriText);
             }
 
             String operatorNumeric;
@@ -1217,18 +1189,6 @@
         }
     }
 
-    /**
-     * @return The current CDMA data connection state. ServiceState.RADIO_TECHNOLOGY_1xRTT or
-     * ServiceState.RADIO_TECHNOLOGY_EVDO is the same as "attached" and
-     * ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached.
-     */
-    /*package*/ int getCurrentCdmaDataConnectionState() {
-        return mDataConnectionState;
-    }
-
-    /**
-    * TODO: In the future, we need remove getCurrentCdmaDataConnectionState
-    */
     public int getCurrentDataConnectionState() {
         return mDataConnectionState;
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
index ce33066..04ee2dd8 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.cdma;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import android.os.Message;
 import android.util.Log;
 
@@ -56,14 +58,11 @@
             recordSize = new int[3];
 
             //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling
-            Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE);
+            AtomicBoolean status = new AtomicBoolean(false);
+            Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
 
             phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
-            try {
-                mLock.wait();
-            } catch (InterruptedException e) {
-                logd("interrupted while trying to load from the RUIM");
-            }
+            waitForResult(status);
         }
 
         return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 3f4cd67..be5c616 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.SystemProperties;
+import android.telephony.PhoneNumberUtils;
 import android.util.Log;
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.SmsHeader;
@@ -806,7 +807,12 @@
          * mechanism, and avoid null pointer exceptions.
          */
 
-        CdmaSmsAddress destAddr = CdmaSmsAddress.parse(destAddrStr);
+        /**
+         * North America Plus Code :
+         * Convert + code to 011 and dial out for international SMS
+         */
+        CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
+                PhoneNumberUtils.cdmaCheckAndProcessPlusCode(destAddrStr));
         if (destAddr == null) return null;
 
         BearerData bearerData = new BearerData();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index f6485a4..1fbc1c1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -608,33 +608,6 @@
         return allowed;
     }
 
-    /**
-     * Release the apnContext
-     *
-     * @param apnContext
-     * @param tearDown
-     * @return none
-     */
-    private void releaseApnContext(ApnContext apnContext, boolean tearDown) {
-        if (apnContext == null) {
-            if (DBG) loge("releaseApnContext: apnContext null should not happen, ignore");
-            return;
-        }
-        DataConnection dc = apnContext.getDataConnection();
-        if (dc == null) {
-            if (DBG) loge("releaseApnContext: apnContext dc == null should not happen, ignore");
-            return;
-        }
-        if (tearDown) {
-            if (DBG) log("releaseApnContext: tearing down");
-            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
-            apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
-        }
-        apnContext.setDataConnection(null);
-        apnContext.setDataConnectionAc(null);
-        return;
-    }
-
     private void setupDataOnReadyApns(String reason) {
         // Only check for default APN state
         for (ApnContext apnContext : mApnContexts.values()) {
@@ -803,17 +776,17 @@
         }
 
         DataConnectionAc dcac = apnContext.getDataConnectionAc();
-        if (dcac != null) {
-            if (tearDown) {
-                apnContext.setState(State.DISCONNECTING);
-                releaseApnContext(apnContext, tearDown);
-            } else {
-                dcac.resetSync();
-                apnContext.setState(State.IDLE);
-                mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-                apnContext.setDataConnection(null);
-                apnContext.setDataConnectionAc(null);
-            }
+        if (tearDown && (dcac != null)) {
+            if (DBG) log("cleanUpConnection: tearing down");
+            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+            apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
+            apnContext.setState(State.DISCONNECTING);
+        } else {
+            if (dcac != null) dcac.resetSync();
+            apnContext.setState(State.IDLE);
+            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+            apnContext.setDataConnection(null);
+            apnContext.setDataConnectionAc(null);
         }
     }
 
@@ -1704,7 +1677,8 @@
                     apnContext.setState(State.FAILED);
                     mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
 
-                    releaseApnContext(apnContext, false);
+                    apnContext.setDataConnection(null);
+                    apnContext.setDataConnectionAc(null);
                     if (DBG) {
                         log("onDataSetupComplete: permanent error apn=%s" + apnString );
                     }
@@ -1739,6 +1713,8 @@
 
         apnContext.setState(State.IDLE);
         apnContext.setApnSetting(null);
+        apnContext.setDataConnection(null);
+        apnContext.setDataConnectionAc(null);
 
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 4352831..93f4b4e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -84,12 +84,6 @@
     private int mNewReasonDataDenied = -1;
 
     /**
-     *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ definitions.
-     */
-    private int networkType = 0;
-    private int newNetworkType = 0;
-
-    /**
      * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by
      * handlePollStateResult to store CREG roaming result.
      */
@@ -628,7 +622,7 @@
                     }
                     newGPRSState = regCodeToServiceState(regState);
                     mDataRoaming = regCodeIsRoaming(regState);
-                    newNetworkType = type;
+                    mNewRadioTechnology = type;
                     newSS.setRadioTechnology(type);
                 break;
 
@@ -748,37 +742,6 @@
         }
     }
 
-    private static String networkTypeToString(int type) {
-        //Network Type from GPRS_REGISTRATION_STATE
-        String ret = "unknown";
-
-        switch (type) {
-            case ServiceState.RADIO_TECHNOLOGY_GPRS:
-                ret = "GPRS";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_EDGE:
-                ret = "EDGE";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_UMTS:
-                ret = "UMTS";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_HSDPA:
-                ret = "HSDPA";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_HSUPA:
-                ret = "HSUPA";
-                break;
-            case ServiceState.RADIO_TECHNOLOGY_HSPA:
-                ret = "HSPA";
-                break;
-            default:
-                sloge("Wrong network type: " + Integer.toString(type));
-                break;
-        }
-
-        return ret;
-    }
-
     private void pollStateDone() {
         if (DBG) {
             log("Poll ServiceState done: " +
@@ -788,8 +751,8 @@
                 " mNewMaxDataCalls=" + mNewMaxDataCalls +
                 " oldReasonDataDenied=" + mReasonDataDenied +
                 " mNewReasonDataDenied=" + mNewReasonDataDenied +
-                " oldType=" + networkTypeToString(networkType) +
-                " newType=" + networkTypeToString(newNetworkType));
+                " oldType=" + ServiceState.radioTechnologyToString(mRadioTechnology) +
+                " newType=" + ServiceState.radioTechnologyToString(mNewRadioTechnology));
         }
 
         boolean hasRegistered =
@@ -808,7 +771,7 @@
                 gprsState == ServiceState.STATE_IN_SERVICE
                 && newGPRSState != ServiceState.STATE_IN_SERVICE;
 
-        boolean hasNetworkTypeChanged = networkType != newNetworkType;
+        boolean hasRadioTechnologyChanged = mRadioTechnology != mNewRadioTechnology;
 
         boolean hasChanged = !newSS.equals(ss);
 
@@ -838,30 +801,32 @@
         // Add an event log when network type switched
         // TODO: we may add filtering to reduce the event logged,
         // i.e. check preferred network setting, only switch to 2G, etc
-        if (hasNetworkTypeChanged) {
+        if (hasRadioTechnologyChanged) {
             int cid = -1;
             GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
             if (loc != null) cid = loc.getCid();
-            EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED, cid, networkType, newNetworkType);
+            EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED, cid, mRadioTechnology,
+                    mNewRadioTechnology);
             if (DBG) {
-                log("RAT switched " + networkTypeToString(networkType) + " -> "
-                    + networkTypeToString(newNetworkType) + " at cell " + cid);
+                log("RAT switched " + ServiceState.radioTechnologyToString(mRadioTechnology) +
+                        " -> " + ServiceState.radioTechnologyToString(mNewRadioTechnology) +
+                        " at cell " + cid);
             }
         }
 
         gprsState = newGPRSState;
         mReasonDataDenied = mNewReasonDataDenied;
         mMaxDataCalls = mNewMaxDataCalls;
-        networkType = newNetworkType;
+        mRadioTechnology = mNewRadioTechnology;
         // this new state has been applied - forget it until we get a new new state
-        newNetworkType = 0;
+        mNewRadioTechnology = 0;
 
 
         newSS.setStateOutOfService(); // clean slate for next time
 
-        if (hasNetworkTypeChanged) {
+        if (hasRadioTechnologyChanged) {
             phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                    networkTypeToString(networkType));
+                    ServiceState.radioTechnologyToString(mRadioTechnology));
         }
 
         if (hasRegistered) {
@@ -949,7 +914,7 @@
             mDetachedRegistrants.notifyRegistrants();
         }
 
-        if (hasNetworkTypeChanged) {
+        if (hasRadioTechnologyChanged) {
             phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED, Phone.APN_TYPE_ALL);
         }
 
@@ -1285,7 +1250,7 @@
      * that could support voice and data simultaneously.
      */
     public boolean isConcurrentVoiceAndDataAllowed() {
-        return (networkType >= ServiceState.RADIO_TECHNOLOGY_UMTS);
+        return (mRadioTechnology >= ServiceState.RADIO_TECHNOLOGY_UMTS);
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 4cd9440..b0bad56 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -45,12 +45,12 @@
 /**
  * {@hide}
  */
-public final class SIMRecords extends IccRecords {
-    static final String LOG_TAG = "GSM";
+public class SIMRecords extends IccRecords {
+    protected static final String LOG_TAG = "GSM";
 
     private static final boolean CRASH_RIL = false;
 
-    private static final boolean DBG = true;
+    protected static final boolean DBG = true;
 
     // ***** Instance Variables
 
@@ -120,13 +120,13 @@
 
     private static final int EVENT_SIM_READY = 1;
     private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
-    private static final int EVENT_GET_IMSI_DONE = 3;
-    private static final int EVENT_GET_ICCID_DONE = 4;
+    protected static final int EVENT_GET_IMSI_DONE = 3;
+    protected static final int EVENT_GET_ICCID_DONE = 4;
     private static final int EVENT_GET_MBI_DONE = 5;
     private static final int EVENT_GET_MBDN_DONE = 6;
     private static final int EVENT_GET_MWIS_DONE = 7;
     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
-    private static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
+    protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
     private static final int EVENT_GET_MSISDN_DONE = 10;
     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
     private static final int EVENT_GET_SPN_DONE = 12;
@@ -147,6 +147,8 @@
     private static final int EVENT_GET_CFIS_DONE = 32;
     private static final int EVENT_GET_CSP_CPHS_DONE = 33;
 
+    protected static final int CSIM_EVENT_BASE = 100;
+
     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
 
     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
@@ -1285,7 +1287,7 @@
         fetchSimRecords();
     }
 
-    private void fetchSimRecords() {
+    protected void fetchSimRecords() {
         recordsRequested = true;
         IccFileHandler iccFh = phone.getIccFileHandler();
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
index 377f8f0..35ba0d1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.gsm;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import android.os.Message;
 import android.util.Log;
 
@@ -56,14 +58,11 @@
             recordSize = new int[3];
 
             //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling
-            Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE);
+            AtomicBoolean status = new AtomicBoolean(false);
+            Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
 
             phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
-            try {
-                mLock.wait();
-            } catch (InterruptedException e) {
-                logd("interrupted while trying to load from the SIM");
-            }
+            waitForResult(status);
         }
 
         return recordSize;
diff --git a/tests/GridLayoutTest/AndroidManifest.xml b/tests/GridLayoutTest/AndroidManifest.xml
index 53ca4ce..1b72357 100644
--- a/tests/GridLayoutTest/AndroidManifest.xml
+++ b/tests/GridLayoutTest/AndroidManifest.xml
@@ -76,6 +76,27 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <activity android:name="AlignmentTest" android:label="AlignmentTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="LinearLayoutTest" android:label="LinearLayoutTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="GridLayoutTest" android:label="GridLayoutTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 
 
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java
new file mode 100644
index 0000000..937eacb
--- /dev/null
+++ b/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.test.layout;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Debug;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public abstract class AbstractLayoutTest extends Activity {
+
+    public static final String[] HORIZONTAL_NAMES = new String[] { "LEFT", "center", "east", "fill" };
+    public static final int[] HORIZONTAL_ALIGNMENTS = new int[] { Gravity.LEFT, Gravity.CENTER, Gravity.RIGHT, Gravity.FILL };
+    public static final String[] VERTICAL_NAMES = new String[] { "north", "center", "baseline", "south", "fill" };
+    public static final int[] VERTICAL_ALIGNMENTS = new int[] { Gravity.TOP, Gravity.CENTER, Gravity.NO_GRAVITY, Gravity.BOTTOM, Gravity.FILL };
+
+    public View create(Context context, String name, int size) {
+        Button result = new Button(context);
+        result.setText(name);
+        result.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                animate(v);
+            }
+        });
+        return result;
+    }
+
+    public abstract ViewGroup create(Context context);
+    public abstract String tag();
+
+    public void animate(View v) {
+        long start = System.currentTimeMillis();
+        int N = 1000;
+        for (int i = 0; i < N; i++) {
+            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+            lp.topMargin = (lp.topMargin + 1) % 31;
+            lp.leftMargin = (lp.leftMargin + 1) % 31;
+
+            v.requestLayout();
+            v.invalidate();
+            ViewGroup p = (ViewGroup) v.getParent();
+            p.layout(0, 0, 1000 + (i % 2), 500 + (i % 2));
+        }
+        Log.d(tag(), "Time: " + (float) (System.currentTimeMillis() - start) / N * 1000 + "mics");
+    }
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(create(getBaseContext()));
+    }
+
+}
\ No newline at end of file
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index 6359903..5e29cf1 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -32,6 +32,7 @@
     public static View create(Context context) {
         GridLayout vg = new GridLayout(context);
         vg.setUseDefaultMargins(true);
+        vg.setMarginsIncludedInAlignment(false);
 
         Group row1 = new Group(1, CENTER);
         Group row2 = new Group(2, CENTER);
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
new file mode 100755
index 0000000..c6f390e
--- /dev/null
+++ b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.test.layout;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.GridLayout;
+import android.widget.TextView;
+
+import static android.widget.GridLayout.*;
+
+public class AlignmentTest  extends Activity {
+
+    public static final String[] HORIZONTAL_NAMES = new String[]{"LEFT", "center", "east", "fill"};
+    public static final Alignment[] HORIZONTAL_ALIGNMENTS = new Alignment[]{LEFT, CENTER, RIGHT, FILL};
+    public static final String[] VERTICAL_NAMES = new String[]{"north", "center", "baseline", "south", "fill"};
+    public static final Alignment[] VERTICAL_ALIGNMENTS = new Alignment[]{TOP, CENTER, BASELINE, BOTTOM, FILL};
+    private static Context CONTEXT;
+
+    public static interface ViewFactory {
+        View create(String name, int size);
+    }
+
+    public static final ViewFactory BUTTON_FACTORY = new ViewFactory() {
+        public View create(String name, int size) {
+            Button result = new Button(CONTEXT);
+            result.setText(name);
+           result.setOnClickListener(new OnClickListener() {
+               @Override
+               public void onClick(View v) {
+                    animate(v);
+               }
+           });
+            return result;
+        }
+    };
+
+    public static final ViewFactory LABEL_FACTORY = new ViewFactory() {
+        public View create(String name, int size) {
+            TextView result = new TextView(CONTEXT);
+            result.setText(name);
+            result.setTextSize(40);
+            return result;
+        }
+    };
+
+    public static final ViewFactory TEXT_FIELD_FACTORY = new ViewFactory() {
+        public View create(String name, int size) {
+            EditText result = new EditText(CONTEXT);
+            result.setText(name);
+            return result;
+        }
+    };
+
+    public static final ViewFactory[] FACTORIES = new ViewFactory[]{BUTTON_FACTORY, LABEL_FACTORY, TEXT_FIELD_FACTORY};
+
+    public static ViewGroup create(Context context1) {
+        CONTEXT = context1;
+        GridLayout container = new GridLayout(context1);
+        container.setUseDefaultMargins(true);
+
+        for (int i = 0; i < VERTICAL_ALIGNMENTS.length; i++) {
+            Alignment va = VERTICAL_ALIGNMENTS[i];
+            for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
+                Alignment ha = HORIZONTAL_ALIGNMENTS[j];
+                Group rowGroup = new Group(i, va);
+                Group colGroup = new Group(j, ha);
+                LayoutParams layoutParams = new LayoutParams(rowGroup, colGroup);
+                container.addView(FACTORIES[(i + j) % FACTORIES.length].create(VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20), layoutParams);
+            }
+        }
+
+        return container;
+    }
+
+    public static void animate(View v) {
+
+        long start = System.currentTimeMillis();
+        int N = 1000;
+        for (int i = 0; i < N; i++) {
+            ViewGroup.LayoutParams lp = v.getLayoutParams();
+            lp.width += 1; // width;
+            lp.height += 1; // height;
+            v.requestLayout();
+            GridLayout p = (GridLayout) v.getParent();
+            p.layout(0, 0, 1000 + (i % 2), 500 + (i % 2));
+        }
+        System.out.println("Time: " + (float) (System.currentTimeMillis() - start) / N * 1000 + "mics");
+    }
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(create(getBaseContext()));
+    }
+
+}
\ No newline at end of file
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
new file mode 100644
index 0000000..b4451e8
--- /dev/null
+++ b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.layout;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+
+import static android.widget.GridLayout.*;
+
+public class GridLayoutTest extends AbstractLayoutTest {
+    public ViewGroup create(Context context) {
+        GridLayout container = new GridLayout(context);
+        container.setOrientation(VERTICAL);
+//        container.setUseDefaultMargins(true);
+
+        for (int i = 0; i < VERTICAL_ALIGNMENTS.length; i++) {
+            int va = VERTICAL_ALIGNMENTS[i];
+            for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
+                int ha = HORIZONTAL_ALIGNMENTS[j];
+                GridLayout.Group rowGroup = new GridLayout.Group(UNDEFINED, null);
+                GridLayout.Group colGroup = new GridLayout.Group(UNDEFINED, null);
+                GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowGroup, colGroup);
+                lp.setGravity(va | ha);
+//                View v = create(VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);
+                View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);
+                container.addView(v, lp);
+            }
+        }
+
+        return container;
+    }
+
+    public String tag() {
+        return GridLayoutTest.class.getName();
+    }
+}
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java
new file mode 100644
index 0000000..fbd1239
--- /dev/null
+++ b/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.layout;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import static android.widget.LinearLayout.*;
+
+public class LinearLayoutTest extends AbstractLayoutTest {
+    public ViewGroup create(Context context) {
+        LinearLayout container = new LinearLayout(context);
+        container.setOrientation(LinearLayout.VERTICAL);
+//        container.setUseDefaultMargins(true);
+
+        for (int i = 0; i < VERTICAL_ALIGNMENTS.length; i++) {
+            int va = VERTICAL_ALIGNMENTS[i];
+            for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
+                int ha = HORIZONTAL_ALIGNMENTS[j];
+                LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                lp.gravity = va | ha;
+//                View v = create(VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);
+                View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);
+                container.addView(v, lp);
+            }
+        }
+
+        return container;
+    }
+
+    public String tag() {
+        return LinearLayoutTest.class.getName();
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index e0f0f05..f015378 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -164,7 +164,7 @@
         }
         
         try {
-            mWm.setAppStartingWindow(null, "foo", 0, null, 0, 0, 0, null, false);
+            mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, null, false);
             fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {