Merge "Work to support saveLayer in new pipeline"
diff --git a/api/current.txt b/api/current.txt
index a1b898f..55b5d52 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35332,8 +35332,10 @@
field public static final int KEYCODE_CLEAR = 28; // 0x1c
field public static final int KEYCODE_COMMA = 55; // 0x37
field public static final int KEYCODE_CONTACTS = 207; // 0xcf
+ field public static final int KEYCODE_COPY = 278; // 0x116
field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
+ field public static final int KEYCODE_CUT = 277; // 0x115
field public static final int KEYCODE_D = 32; // 0x20
field public static final int KEYCODE_DEL = 67; // 0x43
field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
@@ -35451,6 +35453,7 @@
field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
field public static final int KEYCODE_PAIRING = 225; // 0xe1
+ field public static final int KEYCODE_PASTE = 279; // 0x117
field public static final int KEYCODE_PERIOD = 56; // 0x38
field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
field public static final int KEYCODE_PLUS = 81; // 0x51
diff --git a/api/system-current.txt b/api/system-current.txt
index 60d57c6..06cbfa7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -37629,8 +37629,10 @@
field public static final int KEYCODE_CLEAR = 28; // 0x1c
field public static final int KEYCODE_COMMA = 55; // 0x37
field public static final int KEYCODE_CONTACTS = 207; // 0xcf
+ field public static final int KEYCODE_COPY = 278; // 0x116
field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
+ field public static final int KEYCODE_CUT = 277; // 0x115
field public static final int KEYCODE_D = 32; // 0x20
field public static final int KEYCODE_DEL = 67; // 0x43
field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
@@ -37748,6 +37750,7 @@
field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
field public static final int KEYCODE_PAIRING = 225; // 0xe1
+ field public static final int KEYCODE_PASTE = 279; // 0x117
field public static final int KEYCODE_PERIOD = 56; // 0x38
field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
field public static final int KEYCODE_PLUS = 81; // 0x51
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 444548f..ad9058f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -901,8 +901,12 @@
* Tells the underlying networking system that the caller wants to
* begin using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType specifies which network the request pertains to
* @param feature the name of the feature to be used
* @return an integer value representing the outcome of the request.
@@ -952,8 +956,12 @@
* Tells the underlying networking system that the caller is finished
* using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType specifies which network the request pertains to
* @param feature the name of the feature that is no longer needed
* @return an integer value representing the outcome of the request.
@@ -1339,8 +1347,12 @@
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface. An attempt to add a route that
* already exists is ignored, but treated as successful.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType the type of the network over which traffic to the specified
* host is to be routed
* @param hostAddress the IP address of the host to which the route is desired
@@ -1360,8 +1372,12 @@
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface. An attempt to add a route that
* already exists is ignored, but treated as successful.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType the type of the network over which traffic to the specified
* host is to be routed
* @param hostAddress the IP address of the host to which the route is desired
@@ -1561,6 +1577,13 @@
return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
+ /** {@hide} */
+ public static final void enforceChangePermission(Context context) {
+ int uid = Binder.getCallingUid();
+ Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
+ .getPackageNameForUid(context, uid), true /* throwException */);
+ }
+
/** {@hide */
public static final void enforceTetherChangePermission(Context context) {
if (context.getResources().getStringArray(
@@ -1571,8 +1594,8 @@
android.Manifest.permission.CONNECTIVITY_INTERNAL, "ConnectivityService");
} else {
int uid = Binder.getCallingUid();
- Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
- .getPackageNameForUid(context, uid), true);
+ Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings
+ .getPackageNameForUid(context, uid), true /* throwException */);
}
}
@@ -1677,8 +1700,11 @@
* allowed between the tethered devices and this device, though upstream net
* access will of course fail until an upstream network interface becomes
* active.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param iface the interface name to tether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
@@ -1695,8 +1721,11 @@
/**
* Stop tethering the named interface.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param iface the interface name to untether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
@@ -1796,8 +1825,11 @@
* attempt to switch to Rndis and subsequently tether the resulting
* interface on {@code true} or turn off tethering and switch off
* Rndis on {@code false}.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param enable a boolean - {@code true} to enable tethering
* @return error a {@code TETHER_ERROR} value indicating success or failure type
@@ -2467,8 +2499,11 @@
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
* know how to go about satisfing a request with these capabilities.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this
@@ -2490,8 +2525,12 @@
* network is not found within the given time (in milliseconds) the
* {@link NetworkCallback#unavailable} callback is called. The request must
* still be released normally by calling {@link releaseNetworkRequest}.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The callbacks to be utilized for this request. Note
* the callbacks must not be shared - they uniquely specify
@@ -2564,8 +2603,12 @@
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
* know how to go about satisfing a request with these capabilities.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
* to the {@link NetworkCallback#onAvailable} call. Typically
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d601831..11effd0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1434,25 +1434,6 @@
}
/**
- * An app can use this method to check if it is currently allowed to change the network
- * state. In order to be allowed to do so, an app must first declare either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} or
- * {@link android.Manifest.permission#WRITE_SETTINGS} permission in its manifest. If it
- * is currently disallowed, it can prompt the user to grant it this capability through a
- * management UI by sending an Intent with action
- * {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}.
- *
- * @param context A context
- * @return true if the calling app can change the state of network, false otherwise.
- * @hide
- */
- public static boolean canChangeNetworkState(Context context) {
- int uid = Binder.getCallingUid();
- return Settings.isCallingPackageAllowedToChangeNetworkState(context, uid, Settings
- .getPackageNameForUid(context, uid), false);
- }
-
- /**
* System settings, containing miscellaneous system preferences. This
* table holds simple name/value pairs. There are convenience
* functions for accessing individual settings entries.
@@ -8384,7 +8365,7 @@
* write/modify system settings, as the condition differs for pre-M, M+, and
* privileged/preinstalled apps. If the provided uid does not match the
* callingPackage, a negative result will be returned. The caller is expected to have
- * either WRITE_SETTINGS or CHANGE_NETWORK_STATE permission declared.
+ * the WRITE_SETTINGS permission declared.
*
* Note: if the check is successful, the operation of this app will be updated to the
* current time.
@@ -8400,31 +8381,22 @@
/**
* Performs a strict and comprehensive check of whether a calling package is allowed to
* change the state of network, as the condition differs for pre-M, M+, and
- * privileged/preinstalled apps. If the provided uid does not match the
- * callingPackage, a negative result will be returned. The caller is expected to have
- * either of CHANGE_NETWORK_STATE or WRITE_SETTINGS permission declared.
- * @hide
- */
- public static boolean isCallingPackageAllowedToChangeNetworkState(Context context, int uid,
- String callingPackage, boolean throwException) {
- return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
- callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS,
- PM_CHANGE_NETWORK_STATE, false);
- }
-
- /**
- * Performs a strict and comprehensive check of whether a calling package is allowed to
- * change the state of network, as the condition differs for pre-M, M+, and
- * privileged/preinstalled apps. If the provided uid does not match the
- * callingPackage, a negative result will be returned. The caller is expected to have
- * either CHANGE_NETWORK_STATE or WRITE_SETTINGS permission declared.
+ * privileged/preinstalled apps. The caller is expected to have either the
+ * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
+ * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
+ * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
+ * permission and cannot be revoked. See http://b/23597341
*
- * Note: if the check is successful, the operation of this app will be updated to the
- * current time.
+ * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
+ * of this app will be updated to the current time.
* @hide
*/
public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid,
String callingPackage, boolean throwException) {
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS,
PM_CHANGE_NETWORK_STATE, true);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 1c20cab..55cf56f 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -790,8 +790,14 @@
public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275;
/** Key code constant: put device to sleep unless a wakelock is held. */
public static final int KEYCODE_SOFT_SLEEP = 276;
+ /** Key code constant: Cut key. */
+ public static final int KEYCODE_CUT = 277;
+ /** Key code constant: Copy key. */
+ public static final int KEYCODE_COPY = 278;
+ /** Key code constant: Paste key. */
+ public static final int KEYCODE_PASTE = 279;
- private static final int LAST_KEYCODE = KEYCODE_SOFT_SLEEP;
+ private static final int LAST_KEYCODE = KEYCODE_PASTE;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index dae4633..2fabe33 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4260,10 +4260,14 @@
positionAtCursorOffset(offset, false);
}
+ /**
+ * @param offset Cursor offset. Must be in [-1, length].
+ * @param parentScrolled If the parent has been scrolled or not.
+ */
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
- mInWord = !getWordIteratorWithText().isBoundary(offset);
+ mInWord = (offset != -1) && !getWordIteratorWithText().isBoundary(offset);
}
@Override
@@ -4496,10 +4500,14 @@
positionAtCursorOffset(offset, false);
}
+ /**
+ * @param offset Cursor offset. Must be in [-1, length].
+ * @param parentScrolled If the parent has been scrolled or not.
+ */
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
- mInWord = !getWordIteratorWithText().isBoundary(offset);
+ mInWord = (offset != -1) && !getWordIteratorWithText().isBoundary(offset);
}
@Override
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9f6e033..f300741 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1715,12 +1715,12 @@
android:protectionLevel="signature|privileged" />
<!-- Allows applications to change network connectivity state.
- <p>Protection level: signature
+ <p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:description="@string/permdesc_changeNetworkState"
android:label="@string/permlab_changeNetworkState"
- android:protectionLevel="signature|preinstalled|appop|pre23" />
+ android:protectionLevel="normal" />
<!-- Allows an application to clear the caches of all installed
applications on the device.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 90306fd..8e36eb0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1832,6 +1832,9 @@
<enum name="KEYCODE_MEDIA_STEP_FORWARD" value="274" />
<enum name="KEYCODE_MEDIA_STEP_BACKWARD" value="275" />
<enum name="KEYCODE_SOFT_SLEEP" value="276" />
+ <enum name="KEYCODE_CUT" value="277" />
+ <enum name="KEYCODE_COPY" value="278" />
+ <enum name="KEYCODE_PASTE" value="279" />
</attr>
<!-- ***************************************************************** -->
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index e235a99..3ed6a78 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -379,6 +379,7 @@
r, theme, attrs, R.styleable.AnimatedStateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
updateStateFromTypedArray(a);
+ updateDensity(r);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 521c74b..6bf3afd 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -291,6 +291,7 @@
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimationDrawable_visible);
updateStateFromTypedArray(a);
+ updateDensity(r);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 1f7d996..ac72734 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -29,6 +29,7 @@
import android.graphics.Rect;
import android.graphics.PorterDuff.Mode;
import android.os.SystemClock;
+import android.util.DisplayMetrics;
import android.util.LayoutDirection;
import android.util.SparseArray;
import android.view.View;
@@ -581,6 +582,17 @@
return mCurrDrawable;
}
+ /**
+ * Updates the source density based on the resources used to inflate
+ * density-dependent values. Implementing classes should call this method
+ * during inflation.
+ *
+ * @param res the resources used to inflate density-dependent values
+ */
+ final void updateDensity(Resources res) {
+ mDrawableContainerState.updateDensity(res);
+ }
+
@Override
public void applyTheme(Theme theme) {
mDrawableContainerState.applyTheme(theme);
@@ -638,22 +650,22 @@
*/
public abstract static class DrawableContainerState extends ConstantState {
final DrawableContainer mOwner;
- final Resources mRes;
- SparseArray<ConstantStateFuture> mDrawableFutures;
-
+ Resources mSourceRes;
+ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
int mChangingConfigurations;
int mChildrenChangingConfigurations;
+ SparseArray<ConstantStateFuture> mDrawableFutures;
Drawable[] mDrawables;
int mNumChildren;
boolean mVariablePadding = false;
- boolean mPaddingChecked;
+ boolean mCheckedPadding;
Rect mConstantPadding;
boolean mConstantSize = false;
- boolean mComputedConstantSize;
+ boolean mCheckedConstantSize;
int mConstantWidth;
int mConstantHeight;
int mConstantMinimumWidth;
@@ -689,7 +701,13 @@
DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
Resources res) {
mOwner = owner;
- mRes = res != null ? res : orig != null ? orig.mRes : null;
+
+ final Resources sourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);
+ mSourceRes = sourceRes;
+
+ final int densityDpi = sourceRes == null ? 0 : sourceRes.getDisplayMetrics().densityDpi;
+ final int sourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ mDensity = sourceDensity;
if (orig != null) {
mChangingConfigurations = orig.mChangingConfigurations;
@@ -713,21 +731,30 @@
mHasTintList = orig.mHasTintList;
mHasTintMode = orig.mHasTintMode;
- // Cloning the following values may require creating futures.
- mConstantPadding = orig.getConstantPadding();
- mPaddingChecked = true;
+ if (orig.mDensity == sourceDensity) {
+ if (orig.mCheckedPadding) {
+ mConstantPadding = new Rect(orig.mConstantPadding);
+ mCheckedPadding = true;
+ }
- mConstantWidth = orig.getConstantWidth();
- mConstantHeight = orig.getConstantHeight();
- mConstantMinimumWidth = orig.getConstantMinimumWidth();
- mConstantMinimumHeight = orig.getConstantMinimumHeight();
- mComputedConstantSize = true;
+ if (orig.mCheckedConstantSize) {
+ mConstantWidth = orig.mConstantWidth;
+ mConstantHeight = orig.mConstantHeight;
+ mConstantMinimumWidth = orig.mConstantMinimumWidth;
+ mConstantMinimumHeight = orig.mConstantMinimumHeight;
+ mCheckedConstantSize = true;
+ }
+ }
- mOpacity = orig.getOpacity();
- mCheckedOpacity = true;
+ if (orig.mCheckedOpacity) {
+ mOpacity = orig.mOpacity;
+ mCheckedOpacity = true;
+ }
- mStateful = orig.isStateful();
- mCheckedStateful = true;
+ if (orig.mCheckedStateful) {
+ mStateful = orig.mStateful;
+ mCheckedStateful = true;
+ }
// Postpone cloning children and futures until we're absolutely
// sure that we're done computing values for the original state.
@@ -783,8 +810,8 @@
mCheckedOpacity = false;
mConstantPadding = null;
- mPaddingChecked = false;
- mComputedConstantSize = false;
+ mCheckedPadding = false;
+ mCheckedConstantSize = false;
return pos;
}
@@ -863,6 +890,31 @@
return changed;
}
+ /**
+ * Updates the source density based on the resources used to inflate
+ * density-dependent values.
+ *
+ * @param res the resources used to inflate density-dependent values
+ */
+ final void updateDensity(Resources res) {
+ if (mSourceRes != null) {
+ mSourceRes = res;
+ }
+
+ // The density may have changed since the last update (if any). Any
+ // dimension-type attributes will need their default values scaled.
+ final int densityDpi = res.getDisplayMetrics().densityDpi;
+ final int newSourceDensity = densityDpi == 0 ?
+ DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ final int oldSourceDensity = mDensity;
+ mDensity = newSourceDensity;
+
+ if (oldSourceDensity != newSourceDensity) {
+ mCheckedConstantSize = false;
+ mCheckedPadding = false;
+ }
+ }
+
final void applyTheme(Theme theme) {
if (theme != null) {
createAllFutures();
@@ -877,6 +929,8 @@
mChildrenChangingConfigurations |= drawables[i].getChangingConfigurations();
}
}
+
+ updateDensity(theme.getResources());
}
}
@@ -941,7 +995,7 @@
return null;
}
- if ((mConstantPadding != null) || mPaddingChecked) {
+ if ((mConstantPadding != null) || mCheckedPadding) {
return mConstantPadding;
}
@@ -961,7 +1015,7 @@
}
}
- mPaddingChecked = true;
+ mCheckedPadding = true;
return (mConstantPadding = r);
}
@@ -974,7 +1028,7 @@
}
public final int getConstantWidth() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -982,7 +1036,7 @@
}
public final int getConstantHeight() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -990,7 +1044,7 @@
}
public final int getConstantMinimumWidth() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -998,7 +1052,7 @@
}
public final int getConstantMinimumHeight() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -1006,7 +1060,7 @@
}
protected void computeConstantSize() {
- mComputedConstantSize = true;
+ mCheckedConstantSize = true;
createAllFutures();
@@ -1146,10 +1200,10 @@
*/
public Drawable get(DrawableContainerState state) {
final Drawable result;
- if (state.mRes == null) {
+ if (state.mSourceRes == null) {
result = mConstantState.newDrawable();
} else {
- result = mConstantState.newDrawable(state.mRes);
+ result = mConstantState.newDrawable(state.mSourceRes);
}
result.setLayoutDirection(state.mLayoutDirection);
result.setCallback(state.mOwner);
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index b01c643..4ce52d1 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -88,7 +88,13 @@
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
+ updateDensity(r);
+ inflateChildElements(r, parser, attrs, theme);
+ }
+
+ private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+ Theme theme) throws XmlPullParserException, IOException {
int type;
int low = 0;
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 758410a..64a9eb5 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -110,6 +110,7 @@
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.StateListDrawable_visible);
updateStateFromTypedArray(a);
+ updateDensity(r);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index f1eaa23..e161f3d 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -603,7 +603,7 @@
final int densityDpi = a.getResources().getDisplayMetrics().densityDpi;
final int newSourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
final int oldSourceDensity = pathRenderer.mSourceDensity;
- final float densityScale = oldSourceDensity / (float) newSourceDensity;
+ final float densityScale = newSourceDensity / (float) oldSourceDensity;
pathRenderer.mSourceDensity = newSourceDensity;
final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 36a8dac..c0c61db 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -29,7 +29,6 @@
bool Properties::debugOverdraw = false;
bool Properties::showDirtyRegions = false;
bool Properties::skipEmptyFrames = true;
-bool Properties::swapBuffersWithDamage = true;
bool Properties::useBufferAge = true;
bool Properties::enablePartialUpdates = true;
@@ -117,7 +116,6 @@
}
skipEmptyFrames = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE, true);
- swapBuffersWithDamage = property_get_bool(PROPERTY_SWAP_WITH_DAMAGE, true);
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 3512c36..74cd74b 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -142,13 +142,6 @@
#define PROPERTY_SKIP_EMPTY_DAMAGE "debug.hwui.skip_empty_damage"
/**
- * Setting this property will enable or disable usage of EGL_KHR_swap_buffers_with_damage
- * See: https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt
- * Default is "true"
- */
-#define PROPERTY_SWAP_WITH_DAMAGE "debug.hwui.swap_with_damage"
-
-/**
* Controls whether or not HWUI will use the EGL_EXT_buffer_age extension
* to do partial invalidates. Setting this to "false" will fall back to
* using BUFFER_PRESERVED instead
@@ -271,8 +264,6 @@
static bool showDirtyRegions;
// TODO: Remove after stabilization period
static bool skipEmptyFrames;
- // TODO: Remove after stabilization period
- static bool swapBuffersWithDamage;
static bool useBufferAge;
static bool enablePartialUpdates;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index c9b9637..c18e00d 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -322,18 +322,10 @@
}
#endif
-#ifdef EGL_KHR_swap_buffers_with_damage
- if (CC_LIKELY(Properties::swapBuffersWithDamage)) {
- EGLint rects[4];
- frame.map(screenDirty, rects);
- eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects,
- screenDirty.isEmpty() ? 0 : 1);
- } else {
- eglSwapBuffers(mEglDisplay, frame.mSurface);
- }
-#else
- eglSwapBuffers(mEglDisplay, frame.mSurface);
-#endif
+ EGLint rects[4];
+ frame.map(screenDirty, rects);
+ eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects,
+ screenDirty.isEmpty() ? 0 : 1);
EGLint err = eglGetError();
if (CC_LIKELY(err == EGL_SUCCESS)) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index a317ef2..45a8907 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -98,10 +98,12 @@
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
+import com.android.internal.annotations.GuardedBy;
import com.google.common.collect.Lists;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -1743,6 +1745,9 @@
private Context mContext;
private int mCursorCount;
private boolean mIsLoading;
+ @GuardedBy("mPendingDelete")
+ private Boolean mPendingDelete = false;
+ @GuardedBy("mPendingDelete")
private SparseBooleanArray mMarkedForDeletion = new SparseBooleanArray();
private UpdateListener mUpdateListener;
@Nullable private Cursor mCursor;
@@ -1787,35 +1792,39 @@
}
int getItemCount() {
- return mCursorCount - mMarkedForDeletion.size();
+ synchronized(mPendingDelete) {
+ return mCursorCount - mMarkedForDeletion.size();
+ }
}
Cursor getItem(int position) {
- // Items marked for deletion are masked out of the UI. To do this, for every marked
- // item whose position is less than the requested item position, advance the requested
- // position by 1.
- final int originalPos = position;
- final int size = mMarkedForDeletion.size();
- for (int i = 0; i < size; ++i) {
- // It'd be more concise, but less efficient, to iterate over positions while calling
- // mMarkedForDeletion.get. Instead, iterate over deleted entries.
- if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
- ++position;
+ synchronized(mPendingDelete) {
+ // Items marked for deletion are masked out of the UI. To do this, for every marked
+ // item whose position is less than the requested item position, advance the requested
+ // position by 1.
+ final int originalPos = position;
+ final int size = mMarkedForDeletion.size();
+ for (int i = 0; i < size; ++i) {
+ // It'd be more concise, but less efficient, to iterate over positions while calling
+ // mMarkedForDeletion.get. Instead, iterate over deleted entries.
+ if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
+ ++position;
+ }
}
- }
- if (DEBUG && position != originalPos) {
- Log.d(TAG, "Item position adjusted for deletion. Original: " + originalPos
- + " Adjusted: " + position);
- }
+ if (DEBUG && position != originalPos) {
+ Log.d(TAG, "Item position adjusted for deletion. Original: " + originalPos
+ + " Adjusted: " + position);
+ }
- if (position >= mCursorCount) {
- throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
- mCursorCount + " items");
- }
+ if (position >= mCursorCount) {
+ throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
+ mCursorCount + " items");
+ }
- mCursor.moveToPosition(position);
- return mCursor;
+ mCursor.moveToPosition(position);
+ return mCursor;
+ }
}
private boolean isEmpty() {
@@ -1848,17 +1857,19 @@
}
List<DocumentInfo> getDocumentsMarkedForDeletion() {
- final int size = mMarkedForDeletion.size();
- List<DocumentInfo> docs = new ArrayList<>(size);
+ synchronized (mPendingDelete) {
+ final int size = mMarkedForDeletion.size();
+ List<DocumentInfo> docs = new ArrayList<>(size);
- for (int i = 0; i < size; ++i) {
- final int position = mMarkedForDeletion.keyAt(i);
- checkState(position < mCursorCount);
- mCursor.moveToPosition(position);
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
- docs.add(doc);
+ for (int i = 0; i < size; ++i) {
+ final int position = mMarkedForDeletion.keyAt(i);
+ checkState(position < mCursorCount);
+ mCursor.moveToPosition(position);
+ final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
+ docs.add(doc);
+ }
+ return docs;
}
- return docs;
}
/**
@@ -1869,17 +1880,23 @@
* @param selected A selection representing the files to delete.
*/
void markForDeletion(Selection selected) {
- // Only one deletion operation at a time.
- checkState(mMarkedForDeletion.size() == 0);
- // There should never be more to delete than what exists.
- checkState(mCursorCount >= selected.size());
+ synchronized (mPendingDelete) {
+ mPendingDelete = true;
+ // Only one deletion operation at a time.
+ checkState(mMarkedForDeletion.size() == 0);
+ // There should never be more to delete than what exists.
+ checkState(mCursorCount >= selected.size());
- final int size = selected.size();
- for (int i = 0; i < size; ++i) {
- int position = selected.get(i);
- if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion");
- mMarkedForDeletion.append(position, true);
- mViewAdapter.notifyItemRemoved(position);
+ int[] positions = selected.getAll();
+ Arrays.sort(positions);
+
+ // Walk backwards through the set, since we're removing positions.
+ // Otherwise, positions would change after the first modification.
+ for (int p = positions.length - 1; p >= 0; p--) {
+ mMarkedForDeletion.append(positions[p], true);
+ mViewAdapter.notifyItemRemoved(positions[p]);
+ if (DEBUG) Log.d(TAG, "Scheduled " + positions[p] + " for delete.");
+ }
}
}
@@ -1888,17 +1905,24 @@
* unmarked, and restored in the UI. See {@link #markForDeletion(Selection)}.
*/
void undoDeletion() {
- // Iterate over deleted items, temporarily marking them false in the deletion list, and
- // re-adding them to the UI.
- final int size = mMarkedForDeletion.size();
- for (int i = 0; i < size; ++i) {
- final int position = mMarkedForDeletion.keyAt(i);
- mMarkedForDeletion.put(position, false);
- mViewAdapter.notifyItemInserted(position);
+ synchronized (mPendingDelete) {
+ // Iterate over deleted items, temporarily marking them false in the deletion list, and
+ // re-adding them to the UI.
+ final int size = mMarkedForDeletion.size();
+ for (int i = 0; i < size; ++i) {
+ final int position = mMarkedForDeletion.keyAt(i);
+ mMarkedForDeletion.put(position, false);
+ mViewAdapter.notifyItemInserted(position);
+ }
+ resetDeleteData();
}
+ }
- // Then, clear the deletion list.
- mMarkedForDeletion.clear();
+ private void resetDeleteData() {
+ synchronized (mPendingDelete) {
+ mPendingDelete = false;
+ mMarkedForDeletion.clear();
+ }
}
/**
@@ -1909,9 +1933,16 @@
* snackbars) for errors, info, etc.
*/
void finalizeDeletion(DeletionListener listener) {
- final ContentResolver resolver = mContext.getContentResolver();
- DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
- task.execute();
+ synchronized (mPendingDelete) {
+ if (mPendingDelete) {
+ // Necessary to avoid b/25072545. Even when that's resolved, this
+ // is a nice safe thing to day.
+ mPendingDelete = false;
+ final ContentResolver resolver = mContext.getContentResolver();
+ DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
+ task.execute();
+ }
+ }
}
/**
@@ -1968,7 +1999,7 @@
} else {
if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
}
- mMarkedForDeletion.clear();
+ resetDeleteData();
mListener.onCompletion();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index b9c4da1..ef53d53 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -601,6 +601,14 @@
mTotalSelection = new SparseBooleanArray();
}
+ @VisibleForTesting
+ public Selection(int... positions) {
+ this();
+ for (int i = 0; i < positions.length; i++) {
+ add(positions[i]);
+ }
+ }
+
/**
* @param position
* @return true if the position is currently selected.
@@ -624,6 +632,18 @@
}
/**
+ * Returns an unordered array of selected positions.
+ */
+ public int[] getAll() {
+ final int size = size();
+ int[] positions = new int[size];
+ for (int i = 0; i < size; i++) {
+ positions[i] = get(i);
+ }
+ return positions;
+ }
+
+ /**
* @return size of the selection.
*/
public int size() {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
index ace9e27..36d880a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
@@ -32,10 +32,6 @@
import com.android.documentsui.model.DocumentInfo;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-
public class DirectoryFragmentModelTest extends AndroidTestCase {
@@ -117,15 +113,6 @@
assertEquals("0", docs.get(0).documentId);
assertEquals("1", docs.get(1).documentId);
assertEquals("4", docs.get(2).documentId);
-
- TestDeletionListener testListener = new TestDeletionListener();
- model.finalizeDeletion(testListener);
- testListener.waitForDone();
-
- docs = getDocumentInfo(0, 1, 2);
- assertEquals("0", docs.get(0).documentId);
- assertEquals("1", docs.get(1).documentId);
- assertEquals("2", docs.get(2).documentId);
}
// Tests that Model.getItem returns the right items after a deletion is undone.
@@ -149,20 +136,12 @@
};
}
- private void delete(int... items) {
- Selection sel = new Selection();
- for (int item: items) {
- sel.add(item);
- }
- model.markForDeletion(sel);
+ private void delete(int... positions) {
+ model.markForDeletion(new Selection(positions));
}
- private List<DocumentInfo> getDocumentInfo(int... items) {
- Selection sel = new Selection();
- for (int item: items) {
- sel.add(item);
- }
- return model.getDocuments(sel);
+ private List<DocumentInfo> getDocumentInfo(int... positions) {
+ return model.getDocuments(new Selection(positions));
}
private static class DummyListener extends Model.UpdateListener {
@@ -177,20 +156,4 @@
return null;
}
}
-
- private static class TestDeletionListener extends Model.DeletionListener {
- final CountDownLatch mSignal = new CountDownLatch(1);
-
- @Override
- public void onCompletion() {
- mSignal.countDown();
- }
-
- public void waitForDone() {
- try {
- boolean timeout = mSignal.await(10, TimeUnit.SECONDS);
- assertTrue("Timed out waiting for deletion completion", timeout);
- } catch (InterruptedException e) {}
- }
- }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
index cc510a9..9e874bd 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -18,6 +18,7 @@
import android.content.res.Resources;
import android.database.MatrixCursor;
+import android.media.MediaFile;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
import android.provider.DocumentsContract;
@@ -70,30 +71,18 @@
}
static String formatTypeToMimeType(int format) {
- // TODO: Add complete list of mime types.
- switch (format) {
- case MtpConstants.FORMAT_ASSOCIATION:
- return DocumentsContract.Document.MIME_TYPE_DIR;
- case MtpConstants.FORMAT_MP3:
- return "audio/mp3";
- case MtpConstants.FORMAT_EXIF_JPEG:
- return "image/jpeg";
- default:
- return "application/octet-stream";
+ if (format == MtpConstants.FORMAT_ASSOCIATION) {
+ return DocumentsContract.Document.MIME_TYPE_DIR;
+ } else {
+ return MediaFile.getMimeTypeForFormatCode(format);
}
}
- static int mimeTypeToFormatType(String mimeType) {
- // TODO: Add complete list of mime types.
- switch (mimeType.toLowerCase()) {
- case Document.MIME_TYPE_DIR:
- return MtpConstants.FORMAT_ASSOCIATION;
- case "audio/mp3":
- return MtpConstants.FORMAT_MP3;
- case "image/jpeg":
- return MtpConstants.FORMAT_EXIF_JPEG;
- default:
- return MtpConstants.FORMAT_UNDEFINED;
+ static int mimeTypeToFormatType(String fileName, String mimeType) {
+ if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ return MtpConstants.FORMAT_ASSOCIATION;
+ } else {
+ return MediaFile.getFormatCode(fileName, mimeType);
}
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 9d5850b..7883e61 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -242,7 +242,7 @@
new MtpObjectInfo.Builder()
.setStorageId(parentId.mStorageId)
.setParent(parentId.mObjectHandle)
- .setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
+ .setFormat(CursorHelper.mimeTypeToFormatType(displayName, mimeType))
.setName(displayName)
.build(), pipe[1]);
final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b9759dd..c712a56 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1450,10 +1450,7 @@
}
private void enforceChangePermission() {
- int uid = Binder.getCallingUid();
- Settings.checkAndNoteChangeNetworkStateOperation(mContext, uid, Settings
- .getPackageNameForUid(mContext, uid), true);
-
+ ConnectivityManager.enforceChangePermission(mContext);
}
private void enforceTetherAccessPermission() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7df50d5..bb1b6b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5794,7 +5794,7 @@
}
boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
- -100, callerWillRestart, true, doit, evenPersistent,
+ ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
@@ -6110,7 +6110,7 @@
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.makeActive(thread, mProcessStats);
- app.curAdj = app.setAdj = -100;
+ app.curAdj = app.setAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
updateProcessForegroundLocked(app, false, false);
@@ -18057,6 +18057,7 @@
// Examine all activities if not already foreground.
if (!foregroundActivities && activitiesSize > 0) {
+ int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX;
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.app != app) {
@@ -18077,6 +18078,12 @@
app.cached = false;
app.empty = false;
foregroundActivities = true;
+ if (r.task != null && minLayer > 0) {
+ final int layer = r.task.mLayerRank;
+ if (layer >= 0 && minLayer > layer) {
+ minLayer = layer;
+ }
+ }
break;
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -18117,6 +18124,9 @@
}
}
}
+ if (adj == ProcessList.VISIBLE_APP_ADJ) {
+ adj += minLayer;
+ }
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -18326,11 +18336,11 @@
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
+ } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = clientAdj;
} else {
if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
+ adj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
}
}
if (!client.cached) {
@@ -19368,6 +19378,8 @@
uidRec.reset();
}
+ mStackSupervisor.rankTaskLayersIfNeeded();
+
mAdjSeq++;
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a67c274..1721470 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1378,6 +1378,20 @@
return true;
}
+ final int rankTaskLayers(int baseLayer) {
+ int layer = 0;
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ ActivityRecord r = task.topRunningActivityLocked();
+ if (r == null || r.finishing || !r.visible) {
+ task.mLayerRank = -1;
+ } else {
+ task.mLayerRank = baseLayer + layer++;
+ }
+ }
+ return layer;
+ }
+
/**
* Make sure that all activities that need to be visible (that is, they
* currently can be seen by the user) actually are.
@@ -3784,6 +3798,7 @@
task.mLastTimeMoved *= -1;
}
}
+ mStackSupervisor.invalidateTaskLayers();
}
void moveHomeStackTaskToTop(int homeStackTaskType) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 2103b60..54ac58a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -357,6 +357,9 @@
// It will be calculated when the default display gets added.
private int mDefaultMinimalSizeOfResizeableTask = -1;
+ // Whether tasks have moved and we need to rank the tasks before next OOM scoring
+ private boolean mTaskLayersChanged = true;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -3613,6 +3616,24 @@
}
}
+ void invalidateTaskLayers() {
+ mTaskLayersChanged = true;
+ }
+
+ void rankTaskLayersIfNeeded() {
+ if (!mTaskLayersChanged) {
+ return;
+ }
+ mTaskLayersChanged = false;
+ for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) {
+ final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ int baseLayer = 0;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ baseLayer += stacks.get(stackNdx).rankTaskLayers(baseLayer);
+ }
+ }
+ }
+
void clearOtherAppTimeTrackers(AppTimeTracker except) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0e24952..b49370b 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -49,19 +49,22 @@
// OOM adjustments for processes in various states:
+ // Uninitialized value for any major or minor adj fields
+ static final int INVALID_ADJ = -10000;
+
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
- static final int UNKNOWN_ADJ = 16;
+ static final int UNKNOWN_ADJ = 1001;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
- static final int CACHED_APP_MAX_ADJ = 15;
- static final int CACHED_APP_MIN_ADJ = 9;
+ static final int CACHED_APP_MAX_ADJ = 906;
+ static final int CACHED_APP_MIN_ADJ = 900;
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
- static final int SERVICE_B_ADJ = 8;
+ static final int SERVICE_B_ADJ = 800;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
@@ -69,34 +72,35 @@
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
- static final int PREVIOUS_APP_ADJ = 7;
+ static final int PREVIOUS_APP_ADJ = 700;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
- static final int HOME_APP_ADJ = 6;
+ static final int HOME_APP_ADJ = 600;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
- static final int SERVICE_ADJ = 5;
+ static final int SERVICE_ADJ = 500;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 4;
+ static final int HEAVY_WEIGHT_APP_ADJ = 400;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 3;
+ static final int BACKUP_APP_ADJ = 300;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
- static final int PERCEPTIBLE_APP_ADJ = 2;
+ static final int PERCEPTIBLE_APP_ADJ = 200;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
- static final int VISIBLE_APP_ADJ = 1;
+ static final int VISIBLE_APP_ADJ = 100;
+ static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
// This is the process running the current foreground app. We'd really
// rather not kill it!
@@ -104,18 +108,18 @@
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
- static final int PERSISTENT_SERVICE_ADJ = -11;
+ static final int PERSISTENT_SERVICE_ADJ = -700;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
- static final int PERSISTENT_PROC_ADJ = -12;
+ static final int PERSISTENT_PROC_ADJ = -800;
// The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -16;
+ static final int SYSTEM_ADJ = -900;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
- static final int NATIVE_ADJ = -17;
+ static final int NATIVE_ADJ = -1000;
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
@@ -159,7 +163,7 @@
// These must be kept in sync with the definitions in lmkd.c
//
// LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
- // LMK_PROCPRIO <pid> <prio>
+ // LMK_PROCPRIO <pid> <uid> <prio>
// LMK_PROCREMOVE <pid>
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index bd31a21..08203c5 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -171,10 +171,10 @@
boolean debugging; // was app launched for debugging?
boolean waitedForDebugger; // has process show wait for debugger dialog?
Dialog waitDialog; // current wait for debugger dialog
-
+
String shortStringName; // caching of toShortString() result.
String stringName; // caching of toString() result.
-
+
// These reports are generated & stored when an app gets into an error condition.
// They will be "null" when all is OK.
ActivityManager.ProcessErrorStateInfo crashingReport;
@@ -402,7 +402,7 @@
}
}
}
-
+
ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,
String _processName, int _uid) {
mBatteryStats = _batteryStats;
@@ -413,8 +413,8 @@
processName = _processName;
pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));
maxAdj = ProcessList.UNKNOWN_ADJ;
- curRawAdj = setRawAdj = -100;
- curAdj = setAdj = -100;
+ curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
+ curAdj = setAdj = ProcessList.INVALID_ADJ;
persistent = false;
removed = false;
lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
@@ -560,7 +560,7 @@
toShortString(sb);
return shortStringName = sb.toString();
}
-
+
void toShortString(StringBuilder sb) {
sb.append(pid);
sb.append(':');
@@ -585,7 +585,7 @@
}
}
}
-
+
public String toString() {
if (stringName != null) {
return stringName;
@@ -695,7 +695,7 @@
pkgList.put(info.packageName, new ProcessStats.ProcessStateHolder(info.versionCode));
}
}
-
+
public String[] getPackageList() {
int size = pkgList.size();
if (size == 0) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 1999f49..fe87a93 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -221,6 +221,10 @@
// default minimal size.
final int mMinimalSize;
+ // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
+ // This number will be assigned when we evaluate OOM scores for all visible tasks.
+ int mLayerRank = -1;
+
Configuration mOverrideConfig = Configuration.EMPTY;
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 80697ed..b36a22e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -598,8 +598,6 @@
@Override
public Bundle getUserRestrictions(int userId) {
- // checkManageUsersPermission("getUserRestrictions");
-
synchronized (mPackagesLock) {
Bundle restrictions = mUserRestrictions.get(userId);
return restrictions != null ? new Bundle(restrictions) : new Bundle();
@@ -1588,7 +1586,7 @@
public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkManageUsersPermission("Only system can get restrictions for other users/apps");
+ checkManageUsersPermission("get application restrictions for other users/apps");
}
synchronized (mPackagesLock) {
// Read the restrictions from XML
@@ -1599,10 +1597,7 @@
@Override
public void setApplicationRestrictions(String packageName, Bundle restrictions,
int userId) {
- if (UserHandle.getCallingUserId() != userId
- || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkManageUsersPermission("Only system can set restrictions for other users/apps");
- }
+ checkManageUsersPermission("set application restrictions");
synchronized (mPackagesLock) {
if (restrictions == null || restrictions.isEmpty()) {
cleanAppRestrictionsForPackage(packageName, userId);
@@ -1623,7 +1618,7 @@
@Override
public void removeRestrictions() {
- checkManageUsersPermission("Only system can remove restrictions");
+ checkManageUsersPermission("remove restrictions");
final int userHandle = UserHandle.getCallingUserId();
removeRestrictionsForUser(userHandle, true);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d22727d..6b1b6296 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2874,7 +2874,7 @@
/**
* Returns all observed cell information from all radios on the
* device including the primary and neighboring cells. This does
- * not cause or change the rate of PhoneStateListner#onCellInfoChanged.
+ * not cause or change the rate of PhoneStateListener#onCellInfoChanged.
*<p>
* The list can include one or more of {@link android.telephony.CellInfoGsm CellInfoGsm},
* {@link android.telephony.CellInfoCdma CellInfoCdma},
@@ -2888,6 +2888,9 @@
* devices this may return null in which case getCellLocation should
* be called.
*<p>
+ * This API will return valid data for registered cells on devices with
+ * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}
+ *<p>
* @return List of CellInfo or null if info unavailable.
*
* <p>Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}