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 <supports-screens> 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&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&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><objectAnimator></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><objectAnimator></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><set></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><set></code> elements to further group animations together.
+The
+ animations that you want to group together should be children of the <code><set></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>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_add"
+ <item android:id="@+id/menu_save"
android:icon="@drawable/ic_menu_save"
android:title="@string/menu_save"
<b>android:showAsAction="ifRoom|withText"</b> />
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 <include>} element from the palette, which will pop up
+ a layout chooser. When you select the layout to include, it is added with an {@code
+<include>}. 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 <style>} 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) {