Merge "Fix broken Backspace/ForwardDelete tests" into oc-dev
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index deb5b31..588a1bf 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1441,10 +1441,10 @@
System.err.println("Error: no size specified");
return showUsage();
}
- int len = size.length();
long multiplier = 1;
- if (len > 1) {
- char c = size.charAt(len-1);
+ int len = size.length();
+ char c = size.charAt(len - 1);
+ if (c < '0' || c > '9') {
if (c == 'K' || c == 'k') {
multiplier = 1024L;
} else if (c == 'M' || c == 'm') {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dd9db8a..87fcc0a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4275,9 +4275,19 @@
View.mDebugViewAttributes = debugViewAttributes;
// request all activities to relaunch for the changes to take place
- for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
- requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
- false /* preserveWindow */);
+ requestRelaunchAllActivities();
+ }
+ }
+
+ private void requestRelaunchAllActivities() {
+ for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
+ final Activity activity = entry.getValue().activity;
+ if (!activity.mFinished) {
+ try {
+ ActivityManager.getService().requestActivityRelaunch(entry.getKey());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
}
@@ -5116,14 +5126,7 @@
newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;
handleConfigurationChanged(newConfig, null);
- // Schedule all activities to reload
- for (final Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
- final Activity activity = entry.getValue().activity;
- if (!activity.mFinished) {
- requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
- false);
- }
- }
+ requestRelaunchAllActivities();
}
static void freeTextLayoutCachesIfNeeded(int configDiff) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 63c0ef3..1b2543c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2497,7 +2497,6 @@
mBackStack = new ArrayList<BackStackRecord>();
}
mBackStack.add(state);
- reportBackStackChanged();
}
boolean popBackStackState(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index aeccf56..68fce75 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -200,7 +200,7 @@
void setRequestedOrientation(in IBinder token, int requestedOrientation);
int getRequestedOrientation(in IBinder token);
void unbindFinished(in IBinder token, in Intent service, boolean doRebind);
- void setProcessForeground(in IBinder token, int pid, boolean isForeground);
+ void setProcessImportant(in IBinder token, int pid, boolean isForeground, String reason);
void setServiceForeground(in ComponentName className, in IBinder token,
int id, in Notification notification, int flags);
boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 7261dfa..1994206 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -18,6 +18,7 @@
import android.os.PooledStringWriter;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.service.autofill.FillContext;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -1103,6 +1104,9 @@
* Returns the transformation that has been applied to this view, such as a translation
* or scaling. The returned Matrix object is owned by ViewNode; do not modify it.
* Returns null if there is no transformation applied to the view.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public Matrix getTransformation() {
return mMatrix;
@@ -1112,6 +1116,9 @@
* Returns the visual elevation of the view, used for shadowing and other visual
* characterstics, as set by {@link ViewStructure#setElevation
* ViewStructure.setElevation(float)}.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public float getElevation() {
return mElevation;
@@ -1121,6 +1128,9 @@
* Returns the alpha transformation of the view, used to reduce the overall opacity
* of the view's contents, as set by {@link ViewStructure#setAlpha
* ViewStructure.setAlpha(float)}.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public float getAlpha() {
return mAlpha;
@@ -1289,6 +1299,9 @@
/**
* If {@link #getText()} is non-null, this is where the current selection starts.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public int getTextSelectionStart() {
return mText != null ? mText.mTextSelectionStart : -1;
@@ -1298,6 +1311,9 @@
* If {@link #getText()} is non-null, this is where the current selection starts.
* If there is no selection, returns the same value as {@link #getTextSelectionStart()},
* indicating the cursor position.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public int getTextSelectionEnd() {
return mText != null ? mText.mTextSelectionEnd : -1;
@@ -1319,6 +1335,9 @@
* If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
* Note that the text may also contain style spans that modify the color of specific
* parts of the text.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public int getTextBackgroundColor() {
return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
@@ -1329,6 +1348,9 @@
* with it.
* Note that the text may also contain style spans that modify the size of specific
* parts of the text.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public float getTextSize() {
return mText != null ? mText.mTextSize : 0;
@@ -1341,6 +1363,9 @@
* {@link #TEXT_STYLE_UNDERLINE}.
* Note that the text may also contain style spans that modify the style of specific
* parts of the text.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public int getTextStyle() {
return mText != null ? mText.mTextStyle : 0;
@@ -1351,6 +1376,9 @@
* in the array is a formatted line of text, and the value it contains is the offset
* into the text string where that line starts. May return null if there is no line
* information.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public int[] getTextLineCharOffsets() {
return mText != null ? mText.mLineCharOffsets : null;
@@ -1361,6 +1389,9 @@
* in the array is a formatted line of text, and the value it contains is the baseline
* where that text appears in the view. May return null if there is no line
* information.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+ * not for Autofill purposes.
*/
public int[] getTextLineBaselines() {
return mText != null ? mText.mLineBaselines : null;
diff --git a/core/java/android/app/usage/ExternalStorageStats.java b/core/java/android/app/usage/ExternalStorageStats.java
index 83ac779e..d7e570f 100644
--- a/core/java/android/app/usage/ExternalStorageStats.java
+++ b/core/java/android/app/usage/ExternalStorageStats.java
@@ -37,30 +37,46 @@
/**
* Return the total bytes used by all files in the shared/external storage
* hosted on this volume.
+ * <p>
+ * This value only includes data which is isolated for each user on a
+ * multiuser device. Any OBB data shared between users is not accounted in
+ * this value.
*/
public @BytesLong long getTotalBytes() {
return totalBytes;
}
/**
- * Return the total bytes used by audio files in the shared/external storage
- * hosted on this volume.
+ * Return the total bytes used by all audio files in the shared/external
+ * storage hosted on this volume.
+ * <p>
+ * This value only includes data which is isolated for each user on a
+ * multiuser device. This value does not include any app files which are all
+ * accounted under {@link #getAppBytes()}.
*/
public @BytesLong long getAudioBytes() {
return audioBytes;
}
/**
- * Return the total bytes used by video files in the shared/external storage
- * hosted on this volume.
+ * Return the total bytes used by all video files in the shared/external
+ * storage hosted on this volume.
+ * <p>
+ * This value only includes data which is isolated for each user on a
+ * multiuser device. This value does not include any app files which are all
+ * accounted under {@link #getAppBytes()}.
*/
public @BytesLong long getVideoBytes() {
return videoBytes;
}
/**
- * Return the total bytes used by image files in the shared/external storage
- * hosted on this volume.
+ * Return the total bytes used by all image files in the shared/external
+ * storage hosted on this volume.
+ * <p>
+ * This value only includes data which is isolated for each user on a
+ * multiuser device. This value does not include any app files which are all
+ * accounted under {@link #getAppBytes()}.
*/
public @BytesLong long getImageBytes() {
return imageBytes;
@@ -72,6 +88,9 @@
* <p>
* This data is already accounted against individual apps as returned
* through {@link StorageStats}.
+ * <p>
+ * This value only includes data which is isolated for each user on a
+ * multiuser device.
*/
public @BytesLong long getAppBytes() {
return appBytes;
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index e2d4f5b..dc5c7b6 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -43,10 +43,10 @@
interface IBluetoothGatt {
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
- void registerScanner(in IScannerCallback callback);
+ void registerScanner(in IScannerCallback callback, in WorkSource workSource);
void unregisterScanner(in int scannerId);
void startScan(in int scannerId, in ScanSettings settings, in List<ScanFilter> filters,
- in WorkSource workSource, in List scanStorages, in String callingPackage);
+ in List scanStorages, in String callingPackage);
void startScanForIntent(in PendingIntent intent, in ScanSettings settings, in List<ScanFilter> filters,
in String callingPackage);
void stopScanForIntent(in PendingIntent intent, in String callingPackage);
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 5246513..f3f0ae5 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -360,7 +360,7 @@
// Scan stopped.
if (mScannerId == -1) return;
try {
- mBluetoothGatt.registerScanner(this);
+ mBluetoothGatt.registerScanner(this, mWorkSource);
wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS);
} catch (InterruptedException | RemoteException e) {
Log.e(TAG, "application registeration exception", e);
@@ -424,7 +424,7 @@
} else {
mScannerId = scannerId;
mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
- mWorkSource, mResultStorages,
+ mResultStorages,
ActivityThread.currentOpPackageName());
}
} catch (RemoteException e) {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 2b76ae2..d0c6397 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -23,7 +23,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -96,6 +95,9 @@
public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
/** @hide */
+ public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
+
+ /** @hide */
@IntDef(flag = true,
value = {
FLAG_DYNAMIC,
@@ -108,6 +110,7 @@
FLAG_STRINGS_RESOLVED,
FLAG_IMMUTABLE,
FLAG_ADAPTIVE_BITMAP,
+ FLAG_RETURNED_BY_SERVICE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ShortcutFlags {}
@@ -1343,6 +1346,16 @@
return (mFlags & flags) == flags;
}
+ /** @hide */
+ public boolean isReturnedByServer() {
+ return hasFlags(FLAG_RETURNED_BY_SERVICE);
+ }
+
+ /** @hide */
+ public void setReturnedByServer() {
+ addFlags(FLAG_RETURNED_BY_SERVICE);
+ }
+
/** Return whether a shortcut is dynamic. */
public boolean isDynamic() {
return hasFlags(FLAG_DYNAMIC);
@@ -1450,7 +1463,7 @@
/**
* Return whether a shortcut's icon is adaptive bitmap following design guideline
- * defined in {@link AdaptiveIconDrawable}.
+ * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
*
* @hide internal/unit tests only
*/
@@ -1776,6 +1789,9 @@
if (hasStringResourcesResolved()) {
sb.append("Sr");
}
+ if (isReturnedByServer()) {
+ sb.append("V");
+ }
sb.append("]");
sb.append(", packageName=");
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index a7c09b5..e3e0cc5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -618,6 +618,10 @@
/**
* Return all dynamic shortcuts from the caller app.
*
+ * <p>This API is intended to be used for examining what shortcuts are currently published.
+ * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+ * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+ *
* @throws IllegalStateException when the user is locked.
*/
@NonNull
@@ -633,6 +637,10 @@
/**
* Return all static (manifest) shortcuts from the caller app.
*
+ * <p>This API is intended to be used for examining what shortcuts are currently published.
+ * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+ * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+ *
* @throws IllegalStateException when the user is locked.
*/
@NonNull
@@ -697,6 +705,10 @@
/**
* Return all pinned shortcuts from the caller app.
*
+ * <p>This API is intended to be used for examining what shortcuts are currently published.
+ * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+ * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+ *
* @throws IllegalStateException when the user is locked.
*/
@NonNull
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index b21ccf1..042eb87 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -18,6 +18,7 @@
import com.android.internal.R;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -36,8 +37,6 @@
*/
public class FontResourcesParser {
private static final String TAG = "FontResourcesParser";
- private static final int NORMAL_WEIGHT = 400;
- private static final int ITALIC = 1;
// A class represents single entry of font-family in xml file.
public interface FamilyResourceEntry {}
@@ -78,10 +77,10 @@
public static final class FontFileResourceEntry {
private final @NonNull String mFileName;
private int mWeight;
- private boolean mItalic;
+ private int mItalic;
private int mResourceId;
- public FontFileResourceEntry(@NonNull String fileName, int weight, boolean italic) {
+ public FontFileResourceEntry(@NonNull String fileName, int weight, int italic) {
mFileName = fileName;
mWeight = weight;
mItalic = italic;
@@ -95,7 +94,7 @@
return mWeight;
}
- public boolean isItalic() {
+ public int getItalic() {
return mItalic;
}
}
@@ -200,8 +199,10 @@
throws XmlPullParserException, IOException {
AttributeSet attrs = Xml.asAttributeSet(parser);
TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamilyFont);
- int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight, NORMAL_WEIGHT);
- boolean isItalic = ITALIC == array.getInt(R.styleable.FontFamilyFont_fontStyle, 0);
+ int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight,
+ Typeface.RESOLVE_BY_FONT_TABLE);
+ int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle,
+ Typeface.RESOLVE_BY_FONT_TABLE);
String filename = array.getString(R.styleable.FontFamilyFont_font);
array.recycle();
while (parser.next() != XmlPullParser.END_TAG) {
@@ -210,7 +211,7 @@
if (filename == null) {
return null;
}
- return new FontFileResourceEntry(filename, weight, isItalic);
+ return new FontFileResourceEntry(filename, weight, italic);
}
private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 8302ece..65b33e5 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -16,14 +16,17 @@
package android.os;
-import java.util.ArrayList;
+import java.util.Map;
import android.util.Log;
-/** @hide */
+/**
+ * Java API for libvintf.
+ * @hide
+ */
public class VintfObject {
- private static final String LOG_TAG = "VintfObject";
+ /// ---------- OTA
/**
* Slurps all device information (both manifests and both matrices)
@@ -45,4 +48,26 @@
*/
public static native int verify(String[] packageInfo);
+ /// ---------- CTS Device Info
+
+ /**
+ * @return a list of HAL names and versions that is supported by this
+ * device as stated in device and framework manifests. For example,
+ * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
+ * "android.hardware.camera.device@3.2"]. There are no duplicates.
+ */
+ public static native String[] getHalNamesAndVersions();
+
+ /**
+ * @return the BOARD_SEPOLICY_VERS build flag available in device manifest.
+ */
+ public static native String getSepolicyVersion();
+
+ /**
+ * @return a list of VNDK snapshots supported by the framework, as
+ * specified in framework manifest. For example,
+ * [("25.0.5", ["libjpeg.so", "libbase.so"]),
+ * ("25.1.3", ["libjpeg.so", "libbase.so"])]
+ */
+ public static native Map<String, String[]> getVndkSnapshots();
}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 88d17ef..5fd9458 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -15,6 +15,7 @@
*/
package android.service.autofill;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
@@ -156,6 +157,7 @@
*
* <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
*/
+ @CallSuper
@Override
public void onCreate() {
super.onCreate();
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 91f43d6..585f882 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1520,6 +1520,18 @@
/**
* Returns a CharSequence concatenating the specified CharSequences,
* retaining their spans if any.
+ *
+ * If there are no parameters, an empty string will be returned.
+ *
+ * If the number of parameters is exactly one, that parameter is returned as output, even if it
+ * is null.
+ *
+ * If the number of parameters is at least two, any null CharSequence among the parameters is
+ * treated as if it was the string <code>"null"</code>.
+ *
+ * If there are paragraph spans in the source CharSequences that satisfy paragraph boundary
+ * requirements in the sources but would no longer satisfy them in the concatenated
+ * CharSequence, they may get extended in the resulting CharSequence or not retained.
*/
public static CharSequence concat(CharSequence... text) {
if (text.length == 0) {
@@ -1531,35 +1543,29 @@
}
boolean spanned = false;
- for (int i = 0; i < text.length; i++) {
- if (text[i] instanceof Spanned) {
+ for (CharSequence piece : text) {
+ if (piece instanceof Spanned) {
spanned = true;
break;
}
}
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < text.length; i++) {
- sb.append(text[i]);
- }
-
- if (!spanned) {
+ if (spanned) {
+ final SpannableStringBuilder ssb = new SpannableStringBuilder();
+ for (CharSequence piece : text) {
+ // If a piece is null, we append the string "null" for compatibility with the
+ // behavior of StringBuilder and the behavior of the concat() method in earlier
+ // versions of Android.
+ ssb.append(piece == null ? "null" : piece);
+ }
+ return new SpannedString(ssb);
+ } else {
+ final StringBuilder sb = new StringBuilder();
+ for (CharSequence piece : text) {
+ sb.append(piece);
+ }
return sb.toString();
}
-
- SpannableString ss = new SpannableString(sb);
- int off = 0;
- for (int i = 0; i < text.length; i++) {
- int len = text[i].length();
-
- if (text[i] instanceof Spanned) {
- copySpansFrom((Spanned) text[i], 0, len, Object.class, ss, off);
- }
-
- off += len;
- }
-
- return new SpannedString(ss);
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 39f1170..c250ca0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7237,44 +7237,53 @@
RectF position = mAttachInfo.mTmpTransformRect;
position.set(0, 0, mRight - mLeft, mBottom - mTop);
+ mapRectFromViewToScreenCoords(position, clipToParent);
+ outRect.set(Math.round(position.left), Math.round(position.top),
+ Math.round(position.right), Math.round(position.bottom));
+ }
+ /**
+ * Map a rectangle from view-relative coordinates to screen-relative coordinates
+ *
+ * @param rect The rectangle to be mapped
+ * @param clipToParent Whether to clip child bounds to the parent ones.
+ * @hide
+ */
+ public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) {
if (!hasIdentityMatrix()) {
- getMatrix().mapRect(position);
+ getMatrix().mapRect(rect);
}
- position.offset(mLeft, mTop);
+ rect.offset(mLeft, mTop);
ViewParent parent = mParent;
while (parent instanceof View) {
View parentView = (View) parent;
- position.offset(-parentView.mScrollX, -parentView.mScrollY);
+ rect.offset(-parentView.mScrollX, -parentView.mScrollY);
if (clipToParent) {
- position.left = Math.max(position.left, 0);
- position.top = Math.max(position.top, 0);
- position.right = Math.min(position.right, parentView.getWidth());
- position.bottom = Math.min(position.bottom, parentView.getHeight());
+ rect.left = Math.max(rect.left, 0);
+ rect.top = Math.max(rect.top, 0);
+ rect.right = Math.min(rect.right, parentView.getWidth());
+ rect.bottom = Math.min(rect.bottom, parentView.getHeight());
}
if (!parentView.hasIdentityMatrix()) {
- parentView.getMatrix().mapRect(position);
+ parentView.getMatrix().mapRect(rect);
}
- position.offset(parentView.mLeft, parentView.mTop);
+ rect.offset(parentView.mLeft, parentView.mTop);
parent = parentView.mParent;
}
if (parent instanceof ViewRootImpl) {
ViewRootImpl viewRootImpl = (ViewRootImpl) parent;
- position.offset(0, -viewRootImpl.mCurScrollY);
+ rect.offset(0, -viewRootImpl.mCurScrollY);
}
- position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
-
- outRect.set(Math.round(position.left), Math.round(position.top),
- Math.round(position.right), Math.round(position.bottom));
+ rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
}
/**
@@ -7351,10 +7360,12 @@
}
structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
- if (!hasIdentityMatrix()) {
- structure.setTransformation(getMatrix());
+ if (!forAutofill) {
+ if (!hasIdentityMatrix()) {
+ structure.setTransformation(getMatrix());
+ }
+ structure.setElevation(getZ());
}
- structure.setElevation(getZ());
structure.setVisibility(getVisibility());
structure.setEnabled(isEnabled());
if (isClickable()) {
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 209ff09..7362c70 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -102,7 +102,9 @@
string, selectionStartIndex, selectionEndIndex);
final int start = startEnd[0];
final int end = startEnd[1];
- if (start >= 0 && end <= string.length() && start <= end) {
+ if (start <= end
+ && start >= 0 && end <= string.length()
+ && start <= selectionStartIndex && end >= selectionEndIndex) {
final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
final SmartSelection.ClassificationResult[] results =
smartSelection.classifyText(
@@ -144,9 +146,6 @@
final TextClassification classificationResult =
createClassificationResult(
results, string.subSequence(startIndex, endIndex));
- // TODO: Added this log for debug only. Remove before release.
- Log.d(LOG_TAG, String.format(
- "Classification type: %s", classificationResult));
return classificationResult;
}
}
@@ -377,11 +376,6 @@
&& Linkify.sUrlMatchFilter.acceptMatch(text, start, end)) {
flag |= SmartSelection.HINT_FLAG_URL;
}
- // TODO: Added this log for debug only. Remove before release.
- Log.d(LOG_TAG, String.format("Email hint: %b",
- (flag & SmartSelection.HINT_FLAG_EMAIL) != 0));
- Log.d(LOG_TAG, String.format("Url hint: %b",
- (flag & SmartSelection.HINT_FLAG_URL) != 0));
return flag;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index eaf1115..bf44f62 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10136,7 +10136,11 @@
if (lineCount <= 1) {
// Simple case: this is a single line.
final CharSequence text = getText();
- structure.setText(text, getSelectionStart(), getSelectionEnd());
+ if (forAutofill) {
+ structure.setText(text);
+ } else {
+ structure.setText(text, getSelectionStart(), getSelectionEnd());
+ }
} else {
// Complex case: multi-line, could be scrolled or within a scroll container
// so some lines are not visible.
@@ -10172,9 +10176,11 @@
if (expandedBottomLine >= lineCount) {
expandedBottomLine = lineCount - 1;
}
+
// Convert lines into character offsets.
int expandedTopChar = layout.getLineStart(expandedTopLine);
int expandedBottomChar = layout.getLineEnd(expandedBottomLine);
+
// Take into account selection -- if there is a selection, we need to expand
// the text we are returning to include that selection.
final int selStart = getSelectionStart();
@@ -10187,48 +10193,57 @@
expandedBottomChar = selEnd;
}
}
+
// Get the text and trim it to the range we are reporting.
CharSequence text = getText();
if (expandedTopChar > 0 || expandedBottomChar < text.length()) {
text = text.subSequence(expandedTopChar, expandedBottomChar);
}
- structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
- final int[] lineOffsets = new int[bottomLine - topLine + 1];
- final int[] lineBaselines = new int[bottomLine - topLine + 1];
- final int baselineOffset = getBaselineOffset();
- for (int i = topLine; i <= bottomLine; i++) {
- lineOffsets[i - topLine] = layout.getLineStart(i);
- lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+
+ if (forAutofill) {
+ structure.setText(text);
+ } else {
+ structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
+
+ final int[] lineOffsets = new int[bottomLine - topLine + 1];
+ final int[] lineBaselines = new int[bottomLine - topLine + 1];
+ final int baselineOffset = getBaselineOffset();
+ for (int i = topLine; i <= bottomLine; i++) {
+ lineOffsets[i - topLine] = layout.getLineStart(i);
+ lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+ }
+ structure.setTextLines(lineOffsets, lineBaselines);
}
- structure.setTextLines(lineOffsets, lineBaselines);
}
- // Extract style information that applies to the TextView as a whole.
- int style = 0;
- int typefaceStyle = getTypefaceStyle();
- if ((typefaceStyle & Typeface.BOLD) != 0) {
- style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
- }
- if ((typefaceStyle & Typeface.ITALIC) != 0) {
- style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC;
- }
+ if (!forAutofill) {
+ // Extract style information that applies to the TextView as a whole.
+ int style = 0;
+ int typefaceStyle = getTypefaceStyle();
+ if ((typefaceStyle & Typeface.BOLD) != 0) {
+ style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
+ }
+ if ((typefaceStyle & Typeface.ITALIC) != 0) {
+ style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC;
+ }
- // Global styles can also be set via TextView.setPaintFlags().
- int paintFlags = mTextPaint.getFlags();
- if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
- style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
- }
- if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) {
- style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE;
- }
- if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
- style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU;
- }
+ // Global styles can also be set via TextView.setPaintFlags().
+ int paintFlags = mTextPaint.getFlags();
+ if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
+ style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
+ }
+ if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) {
+ style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE;
+ }
+ if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
+ style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU;
+ }
- // TextView does not have its own text background color. A background is either part
- // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
- structure.setTextStyle(getTextSize(), getCurrentTextColor(),
- AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+ // TextView does not have its own text background color. A background is either part
+ // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
+ structure.setTextStyle(getTextSize(), getCurrentTextColor(),
+ AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+ }
}
structure.setHint(getHint());
structure.setInputType(getInputType());
@@ -10385,14 +10400,13 @@
positionInfoStartIndex + positionInfoLength,
viewportToContentHorizontalOffset(), viewportToContentVerticalOffset());
CursorAnchorInfo cursorAnchorInfo = builder.setMatrix(null).build();
- int[] locationOnScreen = getLocationOnScreen();
for (int i = 0; i < positionInfoLength; i++) {
int flags = cursorAnchorInfo.getCharacterBoundsFlags(positionInfoStartIndex + i);
if ((flags & FLAG_HAS_VISIBLE_REGION) == FLAG_HAS_VISIBLE_REGION) {
RectF bounds = cursorAnchorInfo
.getCharacterBounds(positionInfoStartIndex + i);
if (bounds != null) {
- bounds.offset(locationOnScreen[0], locationOnScreen[1]);
+ mapRectFromViewToScreenCoords(bounds, true);
boundingRects[i] = bounds;
}
}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 73886a7..91bc681 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -583,4 +583,8 @@
}
return size - leftIdx;
}
+
+ public static @NonNull String[] defeatNullable(@Nullable String[] val) {
+ return (val != null) ? val : EmptyArray.STRING;
+ }
}
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 033f2df..fa9379e 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -23,23 +23,34 @@
#include <JNIHelp.h>
#include <vintf/VintfObject.h>
+#include <vintf/parse_string.h>
#include <vintf/parse_xml.h>
#include "core_jni_helpers.h"
static jclass gString;
+static jclass gHashMapClazz;
+static jmethodID gHashMapInit;
+static jmethodID gHashMapPut;
namespace android {
+using vintf::HalManifest;
+using vintf::SchemaType;
using vintf::VintfObject;
+using vintf::XmlConverter;
+using vintf::Vndk;
using vintf::gHalManifestConverter;
using vintf::gCompatibilityMatrixConverter;
-using vintf::XmlConverter;
+using vintf::to_string;
-static inline jobjectArray toJavaStringArray(JNIEnv* env, const std::vector<std::string>& v) {
+template<typename V>
+static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
+ size_t i;
+ typename V::const_iterator it;
jobjectArray ret = env->NewObjectArray(v.size(), gString, NULL /* init element */);
- for (size_t i = 0; i < v.size(); ++i) {
- env->SetObjectArrayElement(ret, i, env->NewStringUTF(v[i].c_str()));
+ for (i = 0, it = v.begin(); it != v.end(); ++i, ++it) {
+ env->SetObjectArrayElement(ret, i, env->NewStringUTF(it->c_str()));
}
return ret;
}
@@ -55,7 +66,18 @@
}
}
-static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass clazz)
+static void tryAddHalNamesAndVersions(const HalManifest *manifest,
+ const std::string& description,
+ std::set<std::string> *output) {
+ if (manifest == nullptr) {
+ LOG(WARNING) << __FUNCTION__ << "Cannot get " << description;
+ } else {
+ auto names = manifest->getHalNamesAndVersions();
+ output->insert(names.begin(), names.end());
+ }
+}
+
+static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass)
{
std::vector<std::string> cStrings;
@@ -71,7 +93,7 @@
return toJavaStringArray(env, cStrings);
}
-static jint android_os_VintfObject_verify(JNIEnv *env, jclass clazz, jobjectArray packageInfo) {
+static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
size_t count = env->GetArrayLength(packageInfo);
std::vector<std::string> cPackageInfo{count};
for (size_t i = 0; i < count; ++i) {
@@ -84,20 +106,60 @@
return status;
}
+static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
+ std::set<std::string> halNames;
+ tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(),
+ "device manifest", &halNames);
+ tryAddHalNamesAndVersions(VintfObject::GetFrameworkHalManifest(),
+ "framework manifest", &halNames);
+ return toJavaStringArray(env, halNames);
+}
+
+static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {
+ const HalManifest *manifest = VintfObject::GetDeviceHalManifest();
+ if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) {
+ LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest";
+ return nullptr;
+ }
+ std::string cString = to_string(manifest->sepolicyVersion());
+ return env->NewStringUTF(cString.c_str());
+}
+
+static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {
+ const HalManifest *manifest = VintfObject::GetFrameworkHalManifest();
+ if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) {
+ LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest";
+ return nullptr;
+ }
+ jobject jMap = env->NewObject(gHashMapClazz, gHashMapInit);
+ for (const Vndk &vndk : manifest->vndks()) {
+ std::string key = to_string(vndk.versionRange());
+ env->CallObjectMethod(jMap, gHashMapPut,
+ env->NewStringUTF(key.c_str()), toJavaStringArray(env, vndk.libraries()));
+ }
+ return jMap;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gVintfObjectMethods[] = {
{"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
{"verify", "([Ljava/lang/String;)I", (void*)android_os_VintfObject_verify},
+ {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
+ {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
+ {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
};
-
const char* const kVintfObjectPathName = "android/os/VintfObject";
int register_android_os_VintfObject(JNIEnv* env)
{
gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));
+ gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap"));
+ gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
+ gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
+ "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
NELEM(gVintfObjectMethods));
diff --git a/core/res/res/drawable/sym_def_app_icon.xml b/core/res/res/drawable/sym_def_app_icon.xml
index 0fdb0dd..9c02402 100644
--- a/core/res/res/drawable/sym_def_app_icon.xml
+++ b/core/res/res/drawable/sym_def_app_icon.xml
@@ -2,10 +2,7 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@android:color/white" />
<foreground>
- <inset android:insetLeft="27.7%"
- android:insetTop="27.7%"
- android:insetRight="27.7%"
- android:insetBottom="27.7%">
+ <inset android:inset="27.7%">
<bitmap android:src="@mipmap/sym_def_app_icon"/>
</inset>
</foreground>
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 5e426e8..9c904d1 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -68,19 +68,19 @@
assertEquals(4, fileEntries.length);
FontFileResourceEntry font1 = fileEntries[0];
assertEquals(400, font1.getWeight());
- assertEquals(false, font1.isItalic());
+ assertEquals(0, font1.getItalic());
assertEquals("res/font/samplefont.ttf", font1.getFileName());
FontFileResourceEntry font2 = fileEntries[1];
assertEquals(400, font2.getWeight());
- assertEquals(true, font2.isItalic());
+ assertEquals(1, font2.getItalic());
assertEquals("res/font/samplefont2.ttf", font2.getFileName());
FontFileResourceEntry font3 = fileEntries[2];
assertEquals(800, font3.getWeight());
- assertEquals(false, font3.isItalic());
+ assertEquals(0, font3.getItalic());
assertEquals("res/font/samplefont3.ttf", font3.getFileName());
FontFileResourceEntry font4 = fileEntries[3];
assertEquals(800, font4.getWeight());
- assertEquals(true, font4.isItalic());
+ assertEquals(1, font4.getItalic());
assertEquals("res/font/samplefont4.ttf", font4.getFileName());
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a977072..ee2f1ca 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -308,6 +308,7 @@
Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+ Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
@@ -371,6 +372,8 @@
Settings.Global.WIFI_REENABLE_DELAY_MS,
Settings.Global.WIFI_SAVED_STATE,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
+ Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS,
+ Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
Settings.Global.WIFI_SLEEP_POLICY,
Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 742fd60..7b7031b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -40,6 +40,7 @@
public class TextClassificationManagerTest {
private static final LocaleList LOCALES = LocaleList.forLanguageTags("en");
+ private static final String NO_TYPE = null;
private TextClassificationManager mTcm;
private TextClassifier mClassifier;
@@ -102,6 +103,19 @@
}
@Test
+ public void testSmartSelection_withEmoji() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "\uD83D\uDE02 Hello.";
+ String selected = "Hello";
+ int startIndex = text.indexOf(selected);
+ int endIndex = startIndex + selected.length();
+
+ assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+ isTextSelection(startIndex, endIndex, NO_TYPE));
+ }
+
+ @Test
public void testClassifyText() {
if (isTextClassifierDisabled()) return;
@@ -172,12 +186,17 @@
TextSelection selection = (TextSelection) o;
return startIndex == selection.getSelectionStartIndex()
&& endIndex == selection.getSelectionEndIndex()
- && selection.getEntityCount() > 0
- && type.equals(selection.getEntity(0));
+ && typeMatches(selection, type);
}
return false;
}
+ private boolean typeMatches(TextSelection selection, String type) {
+ return type == null
+ || (selection.getEntityCount() > 0
+ && type.trim().equalsIgnoreCase(selection.getEntity(0)));
+ }
+
@Override
public void describeTo(Description description) {
description.appendValue(
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index abdab39..8a36120 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -23,6 +23,7 @@
import android.annotation.Size;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.StrictMode;
import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -600,6 +601,13 @@
src.position(position);
}
+ private void noteHardwareBitmapSlowCall() {
+ if (getConfig() == Config.HARDWARE) {
+ StrictMode.noteSlowCall("Warning: attempt to read pixels from hardware "
+ + "bitmap, which is very slow operation");
+ }
+ }
+
/**
* Tries to make a new bitmap based on the dimensions of this bitmap,
* setting the new bitmap's config to the one specified, and then copying
@@ -618,6 +626,7 @@
if (config == Config.HARDWARE && isMutable) {
throw new IllegalArgumentException("Hardware bitmaps are always immutable");
}
+ noteHardwareBitmapSlowCall();
Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
if (b != null) {
b.setPremultiplied(mRequestPremultiplied);
@@ -635,6 +644,7 @@
*/
public Bitmap createAshmemBitmap() {
checkRecycled("Can't copy a recycled bitmap");
+ noteHardwareBitmapSlowCall();
Bitmap b = nativeCopyAshmem(mNativePtr);
if (b != null) {
b.setPremultiplied(mRequestPremultiplied);
@@ -652,6 +662,7 @@
*/
public Bitmap createAshmemBitmap(Config config) {
checkRecycled("Can't copy a recycled bitmap");
+ noteHardwareBitmapSlowCall();
Bitmap b = nativeCopyAshmemConfig(mNativePtr, config.nativeInt);
if (b != null) {
b.setPremultiplied(mRequestPremultiplied);
@@ -772,6 +783,7 @@
boolean isHardware = source.getConfig() == Config.HARDWARE;
if (isHardware) {
+ source.noteHardwareBitmapSlowCall();
source = nativeCopyPreserveInternalConfig(source.mNativePtr);
}
@@ -1218,6 +1230,7 @@
if (quality < 0 || quality > 100) {
throw new IllegalArgumentException("quality must be 0..100");
}
+ StrictMode.noteSlowCall("Compression of a bitmap is slow");
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
boolean result = nativeCompress(mNativePtr, format.nativeInt,
quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
@@ -1792,6 +1805,7 @@
*/
public void writeToParcel(Parcel p, int flags) {
checkRecycled("Can't parcel a recycled bitmap");
+ noteHardwareBitmapSlowCall();
if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
throw new RuntimeException("native writeToParcel failed");
}
@@ -1838,6 +1852,7 @@
public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
checkRecycled("Can't extractAlpha on a recycled bitmap");
long nativePaint = paint != null ? paint.getNativeInstance() : 0;
+ noteHardwareBitmapSlowCall();
Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
if (bm == null) {
throw new RuntimeException("Failed to extractAlpha on Bitmap");
@@ -1853,6 +1868,8 @@
*/
public boolean sameAs(Bitmap other) {
checkRecycled("Can't call sameAs on a recycled bitmap!");
+ noteHardwareBitmapSlowCall();
+ other.noteHardwareBitmapSlowCall();
if (this == other) return true;
if (other == null) return false;
if (other.isRecycled()) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index f38d8d2..79898bc 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -233,8 +233,7 @@
// TODO: Add ttc and variation font support. (b/37853920)
if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
- fontFile.getWeight(), fontFile.isItalic() ? STYLE_ITALIC : STYLE_NORMAL,
- null /* axes */)) {
+ fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) {
return null;
}
}
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index bc40191..443aa49 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -188,19 +188,19 @@
// Inset attribute may be overridden by more specific attributes.
if (a.hasValue(R.styleable.InsetDrawable_inset)) {
- final InsetValue inset = getInset(a, R.styleable.InsetDrawable_inset, 0);
+ final InsetValue inset = getInset(a, R.styleable.InsetDrawable_inset, new InsetValue());
state.mInsetLeft = inset;
state.mInsetTop = inset;
state.mInsetRight = inset;
state.mInsetBottom = inset;
}
- state.mInsetLeft = getInset(a, R.styleable.InsetDrawable_insetLeft, 0);
- state.mInsetTop = getInset(a, R.styleable.InsetDrawable_insetTop, 0);
- state.mInsetRight = getInset(a, R.styleable.InsetDrawable_insetRight, 0);
- state.mInsetBottom = getInset(a, R.styleable.InsetDrawable_insetBottom, 0);
+ state.mInsetLeft = getInset(a, R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
+ state.mInsetTop = getInset(a, R.styleable.InsetDrawable_insetTop, state.mInsetTop);
+ state.mInsetRight = getInset(a, R.styleable.InsetDrawable_insetRight, state.mInsetRight);
+ state.mInsetBottom = getInset(a, R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
}
- private InsetValue getInset(@NonNull TypedArray a, int index, int defaultValue) {
+ private InsetValue getInset(@NonNull TypedArray a, int index, InsetValue defaultValue) {
if (a.hasValue(index)) {
TypedValue tv = a.peekValue(index);
if (tv.type == TypedValue.TYPE_FRACTION) {
@@ -210,10 +210,13 @@
}
return new InsetValue(f, 0);
} else {
- return new InsetValue(0f, a.getDimensionPixelOffset(index, defaultValue));
+ int dimension = a.getDimensionPixelOffset(index, 0);
+ if (dimension != 0) {
+ return new InsetValue(0, dimension);
+ }
}
}
- return new InsetValue();
+ return defaultValue;
}
private void getInsets(Rect out) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d7f75fc..d765584 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -486,7 +486,6 @@
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
if (isHardware()) {
- ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
outBitmap->allocPixels(info());
uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
return;
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index ccdf5ae..c78c99f 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -705,6 +705,8 @@
}
nativeDetachImage(image);
+ si.clearSurfacePlanes();
+ si.mPlanes = null;
si.setDetached(true);
}
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 349c9cb..2b7309f 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -359,28 +359,14 @@
}
ImageReader prevOwner = (ImageReader) image.getOwner();
- // Only do the image attach for PRIVATE format images for now. Do the image
- // copy for other formats. TODO: use attach for other formats to
- // improve the performance, and fall back to copy when attach/detach
- // fails. Right now, detach is guaranteed to fail as the buffer is
- // locked when ImageReader#acquireNextImage is called. See bug 19962027.
- if (image.getFormat() == ImageFormat.PRIVATE) {
- prevOwner.detachImage(image);
- attachAndQueueInputImage(image);
- // This clears the native reference held by the original owner.
- // When this Image is detached later by this ImageWriter, the
- // native memory won't be leaked.
- image.close();
- return;
- } else {
- Image inputImage = dequeueInputImage();
- inputImage.setTimestamp(image.getTimestamp());
- inputImage.setCropRect(image.getCropRect());
- ImageUtils.imageCopy(image, inputImage);
- image.close();
- image = inputImage;
- ownedByMe = true;
- }
+
+ prevOwner.detachImage(image);
+ attachAndQueueInputImage(image);
+ // This clears the native reference held by the original owner.
+ // When this Image is detached later by this ImageWriter, the
+ // native memory won't be leaked.
+ image.close();
+ return;
}
Rect crop = image.getCropRect();
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index ed5fbcf..b5ea632 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -499,30 +499,23 @@
sp<Surface> surface = ctx->getProducer();
status_t res = OK;
- if (!isFormatOpaque(imageFormat)) {
- // TODO: need implement, see b/19962027
- jniThrowRuntimeException(env,
- "nativeAttachImage for non-opaque image is not implement yet!!!");
- return -1;
- }
-
- if (!isFormatOpaque(ctx->getBufferFormat())) {
+ if (isFormatOpaque(imageFormat) != isFormatOpaque(ctx->getBufferFormat())) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Trying to attach an opaque image into a non-opaque ImageWriter");
+ "Trying to attach an opaque image into a non-opaque ImageWriter, or vice versa");
return -1;
}
// Image is guaranteed to be from ImageReader at this point, so it is safe to
// cast to BufferItem pointer.
- BufferItem* opaqueBuffer = reinterpret_cast<BufferItem*>(nativeBuffer);
- if (opaqueBuffer == NULL) {
+ BufferItem* buffer = reinterpret_cast<BufferItem*>(nativeBuffer);
+ if (buffer == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Image is not initialized or already closed");
return -1;
}
// Step 1. Attach Image
- res = surface->attachBuffer(opaqueBuffer->mGraphicBuffer.get());
+ res = surface->attachBuffer(buffer->mGraphicBuffer.get());
if (res != OK) {
ALOGE("Attach image failed: %s (%d)", strerror(-res), res);
switch (res) {
@@ -559,7 +552,7 @@
}
// Step 3. Queue Image.
- res = anw->queueBuffer(anw.get(), opaqueBuffer->mGraphicBuffer.get(), /*fenceFd*/
+ res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/
-1);
if (res != OK) {
ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
@@ -817,4 +810,3 @@
return (ret1 || ret2);
}
-
diff --git a/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
new file mode 100644
index 0000000..766c42b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
@@ -0,0 +1,44 @@
+package com.android.settingslib;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Toast;
+
+/**
+ * A touch listener which consumes touches when another window is partly or wholly obscuring the
+ * window containing the view this listener is attached to.
+ * Optionally accepts a string to show the user as a toast when consuming an insecure touch
+ */
+public class SecureTouchListener implements View.OnTouchListener {
+
+ private static final long TAP_DEBOUNCE_TIME = 2000;
+ private long mLastToastTime = 0;
+ private String mWarningText;
+
+ public SecureTouchListener() {
+ this(null);
+ }
+
+ public SecureTouchListener(String warningText) {
+ mWarningText = warningText;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0
+ || (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0) {
+ if (mWarningText != null) {
+ // Show a toast warning the user
+ final long currentTime = SystemClock.uptimeMillis();
+ if (currentTime - mLastToastTime > TAP_DEBOUNCE_TIME) {
+ mLastToastTime = currentTime;
+ Toast.makeText(v.getContext(), mWarningText, Toast.LENGTH_SHORT).show();
+ }
+ }
+ // Consume the touch event
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index ea28fe6..5a57e69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -152,6 +152,12 @@
final MeasurementDetails details = new MeasurementDetails();
if (mVolume == null) return details;
+ if (mVolume.getType() == VolumeInfo.TYPE_PUBLIC) {
+ details.totalSize = mVolume.getPath().getTotalSpace();
+ details.availSize = mVolume.getPath().getUsableSpace();
+ return details;
+ }
+
try {
details.totalSize = mStats.getTotalBytes(mVolume.fsUuid);
details.availSize = mStats.getFreeBytes(mVolume.fsUuid);
@@ -161,7 +167,6 @@
return details;
}
-
final long finishTotal = SystemClock.elapsedRealtime();
Log.d(TAG, "Measured total storage in " + (finishTotal - start) + "ms");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4b304b2..14e2a85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1142,28 +1142,55 @@
} finally {
Binder.restoreCallingIdentity(token);
}
+
+ final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
+ SETTINGS_TYPE_SSAID, owningUserId);
+
if (instantSsaid != null) {
// Use the stored value if it is still valid.
if (ssaid != null && instantSsaid.equals(ssaid.getValue())) {
- return ssaid;
+ return mascaradeSsaidSetting(ssaidSettings, ssaid);
}
// The value has changed, update the stored value.
- final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
- SETTINGS_TYPE_SSAID, owningUserId);
final boolean success = ssaidSettings.insertSettingLocked(name, instantSsaid, null,
true, callingPkg.packageName);
if (!success) {
throw new IllegalStateException("Failed to update instant app android id");
}
- return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId, name);
+ Setting setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID,
+ owningUserId, name);
+ return mascaradeSsaidSetting(ssaidSettings, setting);
}
// Lazy initialize ssaid if not yet present in ssaid table.
if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
- return mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
+ Setting setting = mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
+ return mascaradeSsaidSetting(ssaidSettings, setting);
}
- return ssaid;
+ return mascaradeSsaidSetting(ssaidSettings, ssaid);
+ }
+
+ private Setting mascaradeSsaidSetting(SettingsState settingsState, Setting ssaidSetting) {
+ // SSAID settings are located in a dedicated table for internal bookkeeping
+ // but for the world they reside in the secure table, so adjust the key here.
+ // We have a special name when looking it up but want the world to see it as
+ // "android_id".
+ if (ssaidSetting != null) {
+ return settingsState.new Setting(ssaidSetting) {
+ @Override
+ public int getKey() {
+ final int userId = getUserIdFromKey(super.getKey());
+ return makeKey(SETTINGS_TYPE_SECURE, userId);
+ }
+
+ @Override
+ public String getName() {
+ return Settings.Secure.ANDROID_ID;
+ }
+ };
+ }
+ return null;
}
private boolean insertSecureSetting(String name, String value, String tag,
@@ -1173,7 +1200,6 @@
+ ", " + tag + ", " + makeDefault + ", " + requestingUserId
+ ", " + forceNotify + ")");
}
-
return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
MUTATION_OPERATION_INSERT, forceNotify, 0);
}
@@ -1879,6 +1905,7 @@
Bundle result = new Bundle();
result.putString(Settings.NameValueTable.VALUE,
!setting.isNull() ? setting.getValue() : null);
+
mSettingsRegistry.mGenerationRegistry.addGenerationData(result, setting.getKey());
return result;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index d5cf1dd..5afa53f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -132,9 +132,6 @@
}
case MESSAGE_EXPAND_PIP: {
mListeners.forEach(l -> l.onPipExpand());
- // Preemptively mark the menu as invisible once we expand the PiP, but don't
- // resize as we will be animating the stack
- onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
break;
}
case MESSAGE_MINIMIZE_PIP: {
@@ -143,9 +140,6 @@
}
case MESSAGE_DISMISS_PIP: {
mListeners.forEach(l -> l.onPipDismiss());
- // Preemptively mark the menu as invisible once we dismiss the PiP, but don't
- // resize as we'll be removing the stack in place
- onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
break;
}
case MESSAGE_SHOW_MENU: {
@@ -308,6 +302,15 @@
}
/**
+ * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
+ * stack and don't want to trigger a resize which can animate the stack in a conflicting way
+ * (ie. when manually expanding or dismissing).
+ */
+ public void hideMenuWithoutResize() {
+ onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
+ }
+
+ /**
* @return the current menu state.
*/
public int getMenuState() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 5121c8d..590e3c6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -77,6 +77,7 @@
private SurfaceFlingerVsyncChoreographer mVsyncChoreographer;
private Handler mHandler;
+ private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
private FlingAnimationUtils mFlingAnimationUtils;
@@ -93,10 +94,12 @@
};
public PipMotionHelper(Context context, IActivityManager activityManager,
- PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) {
+ PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
+ FlingAnimationUtils flingAnimationUtils) {
mContext = context;
mHandler = BackgroundThread.getHandler();
mActivityManager = activityManager;
+ mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFlingAnimationUtils = flingAnimationUtils;
mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(),
@@ -148,6 +151,7 @@
*/
void expandPip(boolean skipAnimation) {
cancelAnimations();
+ mMenuController.hideMenuWithoutResize();
mHandler.post(() -> {
try {
if (skipAnimation) {
@@ -168,6 +172,7 @@
*/
void dismissPip() {
cancelAnimations();
+ mMenuController.hideMenuWithoutResize();
mHandler.post(() -> {
try {
mActivityManager.removeStack(PINNED_STACK_ID);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 9c7e3986..71d3d35 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -191,8 +191,8 @@
mGestures = new PipTouchGesture[] {
mDefaultMovementGesture
};
- mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
- mFlingAnimationUtils);
+ mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mMenuController,
+ mSnapAlgorithm, mFlingAnimationUtils);
mExpandedShortestEdgeSize = context.getResources().getDimensionPixelSize(
R.dimen.pip_expanded_shortest_edge_size);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c1859fe..badbcb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2489,29 +2489,28 @@
}
StringBuilder flagdbg = new StringBuilder();
- flagdbg.append("disable: < ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
- flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
- flagdbg.append(((diff1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
- flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
- : "quick_settings");
- flagdbg.append(((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
- flagdbg.append(">");
+ flagdbg.append("disable<");
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
+ flagdbg.append('>');
Log.d(TAG, flagdbg.toString());
if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index a2d1baf..c726189 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -47,6 +47,11 @@
public void onPhoneStateChanged(int phoneState) {
update();
}
+
+ @Override
+ public void onRefreshCarrierInfo() {
+ update();
+ }
};
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ff99b19..f37bfac 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3957,6 +3957,11 @@
// OS: O
RUNNING_BACKGROUND_APPS_DIALOG = 944;
+ // FIELD - The delay from the start of the transition until we just call bindApplication on the
+ // client.
+ // OS: O
+ APP_TRANSITION_BIND_APPLICATION_DELAY_MS = 945;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index ac81565..b2712ff 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -373,11 +373,6 @@
}
private void onPackageBroadcastReceived(Intent intent, int userId) {
- if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
- isProfileWithLockedParent(userId)) {
- return;
- }
-
final String action = intent.getAction();
boolean added = false;
boolean changed = false;
@@ -408,7 +403,11 @@
}
synchronized (mLock) {
- ensureGroupStateLoadedLocked(userId);
+ if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
+ isProfileWithLockedParent(userId)) {
+ return;
+ }
+ ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
Bundle extras = intent.getExtras();
@@ -844,7 +843,7 @@
mSecurityPolicy.enforceCallFromPackage(callingPackage);
synchronized (mLock) {
- ensureGroupStateLoadedLocked(userId);
+ ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
// NOTE: The lookup is enforcing security across users by making
// sure the caller can only access hosts it owns.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index b536ad9..9081746 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -213,7 +213,7 @@
if (!doit) {
return true;
}
- handleActiveAutofillServiceRemoved(getChangingUserId());
+ removeCachedServiceLocked(getChangingUserId());
}
}
}
@@ -602,6 +602,31 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ boolean showHistory = true;
+ boolean uiOnly = false;
+ if (args != null) {
+ for (String arg : args) {
+ switch(arg) {
+ case "--no-history":
+ showHistory = false;
+ break;
+ case "--ui-only":
+ uiOnly = true;
+ break;
+ case "--help":
+ pw.println("Usage: dumpsys autofill [--ui-only|--no-history]");
+ return;
+ default:
+ throw new IllegalArgumentException("Invalid dump arg: " + arg);
+ }
+ }
+ }
+
+ if (uiOnly) {
+ mUi.dump(pw);
+ return;
+ }
+
boolean oldDebug = sDebug;
try {
synchronized (mLock) {
@@ -624,8 +649,10 @@
}
mUi.dump(pw);
}
- pw.println("Requests history:");
- mRequestsHistory.reverseDump(fd, pw, args);
+ if (showHistory) {
+ pw.println("Requests history:");
+ mRequestsHistory.reverseDump(fd, pw, args);
+ }
} finally {
setDebugLocked(oldDebug);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4507eae..3ab8b8d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -19,17 +19,21 @@
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;
+import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AppGlobals;
+import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -46,6 +50,7 @@
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -72,6 +77,9 @@
private static final String TAG = "AutofillManagerServiceImpl";
private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
+ /** Minimum interval to prune abandoned sessions */
+ private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
+
static final int MSG_SERVICE_SAVE = 1;
private final int mUserId;
@@ -104,10 +112,10 @@
mHandlerCallback, true);
/**
- * Cache of pending {@link Session}s, keyed by {@code activityToken}.
+ * Cache of pending {@link Session}s, keyed by sessionId.
*
* <p>They're kept until the {@link AutofillService} finished handling a request, an error
- * occurs, or the session times out.
+ * occurs, or the session is abandoned.
*/
@GuardedBy("mLock")
private final SparseArray<Session> mSessions = new SparseArray<>();
@@ -116,6 +124,9 @@
@GuardedBy("mLock")
private FillEventHistory mEventHistory;
+ /** When was {@link PruneTask} last executed? */
+ private long mLastPrune = 0;
+
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
int userId, AutoFillUI ui, boolean disabled) {
mContext = context;
@@ -260,6 +271,9 @@
return 0;
}
+ // Occasionally clean up abandoned sessions
+ pruneAbandonedSessionsLocked();
+
final Session newSession = createSessionByTokenLocked(activityToken, uid, windowToken,
appCallbackToken, hasCallback, flags, packageName);
if (newSession == null) {
@@ -277,6 +291,20 @@
return newSession.id;
}
+ /**
+ * Remove abandoned sessions if needed.
+ */
+ private void pruneAbandonedSessionsLocked() {
+ long now = System.currentTimeMillis();
+ if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
+ mLastPrune = now;
+
+ if (mSessions.size() > 0) {
+ (new PruneTask()).execute();
+ }
+ }
+ }
+
void finishSessionLocked(int sessionId, int uid) {
if (!isEnabled()) {
return;
@@ -513,6 +541,7 @@
pw.print(prefix); pw.print("Default component: ");
pw.println(mContext.getString(R.string.config_defaultAutofillService));
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+ pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
final int size = mSessions.size();
if (size == 0) {
@@ -604,4 +633,62 @@
+ ", component=" + (mInfo != null
? mInfo.getServiceInfo().getComponentName() : null) + "]";
}
+
+ /** Task used to prune abandoned session */
+ private class PruneTask extends AsyncTask<Void, Void, Void> {
+ @Override
+ protected Void doInBackground(Void... ignored) {
+ int numSessionsToRemove;
+ ArrayMap<IBinder, Integer> sessionsToRemove;
+
+ synchronized (mLock) {
+ numSessionsToRemove = mSessions.size();
+ sessionsToRemove = new ArrayMap<>(numSessionsToRemove);
+
+ for (int i = 0; i < numSessionsToRemove; i++) {
+ Session session = mSessions.valueAt(i);
+
+ sessionsToRemove.put(session.getActivityTokenLocked(), session.id);
+ }
+ }
+
+ IActivityManager am = ActivityManager.getService();
+
+ // Only remove sessions which's activities are not known to the activity manager anymore
+ for (int i = 0; i < numSessionsToRemove; i++) {
+ try {
+ // The activity manager cannot resolve activities that have been removed
+ if (am.getActivityClassForToken(sessionsToRemove.keyAt(i)) != null) {
+ sessionsToRemove.removeAt(i);
+ i--;
+ numSessionsToRemove--;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Cannot figure out if activity is finished", e);
+ }
+ }
+
+ synchronized (mLock) {
+ for (int i = 0; i < numSessionsToRemove; i++) {
+ Session sessionToRemove = mSessions.get(sessionsToRemove.valueAt(i));
+
+ if (sessionToRemove != null) {
+ if (sessionToRemove.isSavingLocked()) {
+ if (sVerbose) {
+ Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
+ }
+ } else {
+ if (sDebug) {
+ Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
+ + sessionToRemove.getActivityTokenLocked() + ")");
+ }
+ sessionToRemove.removeSelfLocked();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 23b734a..3c85034 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -177,6 +177,10 @@
@GuardedBy("mLock")
private boolean mDestroyed;
+ /** Whether the session is currently saving */
+ @GuardedBy("mLock")
+ private boolean mIsSaving;
+
/**
* Receiver of assist data from the app's {@link Activity}.
*/
@@ -361,7 +365,7 @@
*
* @return The activity token
*/
- IBinder getActivityTokenLocked() {
+ @NonNull IBinder getActivityTokenLocked() {
return mActivityToken;
}
@@ -474,6 +478,8 @@
@Override
public void onSaveRequestSuccess(@NonNull String servicePackageName) {
synchronized (mLock) {
+ mIsSaving = false;
+
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
+ id + " destroyed");
@@ -496,6 +502,8 @@
public void onSaveRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName) {
synchronized (mLock) {
+ mIsSaving = false;
+
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
+ id + " destroyed");
@@ -596,6 +604,8 @@
@Override
public void cancelSave() {
synchronized (mLock) {
+ mIsSaving = false;
+
if (mDestroyed) {
Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
+ id + " destroyed");
@@ -831,6 +841,8 @@
if (atLeastOneChanged) {
mService.setSaveShown();
getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName);
+
+ mIsSaving = true;
return false;
}
}
@@ -844,6 +856,13 @@
}
/**
+ * Returns whether the session is currently showing the save UI
+ */
+ boolean isSavingLocked() {
+ return mIsSaving;
+ }
+
+ /**
* Calls service when user requested save.
*/
void callSaveLocked() {
@@ -1043,6 +1062,9 @@
}
break;
case ACTION_VIEW_ENTERED:
+ if (sVerbose && virtualBounds != null) {
+ Slog.w(TAG, "entered on virtual child " + id + ": " + virtualBounds);
+ }
requestNewFillResponseIfNecessaryLocked(id, viewState, flags);
// Remove the UI if the ViewState has changed.
@@ -1346,6 +1368,7 @@
pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+ pw.print(prefix); pw.print("mIsSaving: "); pw.println(mIsSaving);
final String prefix2 = prefix + " ";
for (Map.Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 086742e..7428460 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -264,6 +264,10 @@
public void onDestroy() {
if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+
+ if (mCallback != null) {
+ mCallback.cancelSave();
+ }
}
mMetricsLogger.write(log);
}
@@ -282,13 +286,18 @@
pw.println("Autofill UI");
final String prefix = " ";
final String prefix2 = " ";
- pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
if (mFillUi != null) {
pw.print(prefix); pw.println("showsFillUi: true");
mFillUi.dump(pw, prefix2);
} else {
pw.print(prefix); pw.println("showsFillUi: false");
}
+ if (mSaveUi != null) {
+ pw.print(prefix); pw.println("showsSaveUi: true");
+ mSaveUi.dump(pw, prefix2);
+ } else {
+ pw.print(prefix); pw.println("showsSaveUi: false");
+ }
}
@android.annotation.UiThread
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index dd297a6..922962f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -398,6 +398,7 @@
}
return false;
}
+
}
public void dump(PrintWriter pw, String prefix) {
@@ -408,5 +409,21 @@
pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+ pw.print(prefix); pw.print("mWindow: ");
+ if (mWindow == null) {
+ pw.println("N/A");
+ } else {
+ final String prefix2 = prefix + " ";
+ pw.println();
+ pw.print(prefix2); pw.print("showing: "); pw.println(mWindow.mShowing);
+ pw.print(prefix2); pw.print("view: "); pw.println(mWindow.mContentView);
+ pw.print(prefix2); pw.print("screen coordinates: ");
+ if (mWindow.mContentView == null) {
+ pw.println("N/A");
+ } else {
+ final int[] coordinates = mWindow.mContentView.getLocationOnScreen();
+ pw.print(coordinates[0]); pw.print("x"); pw.println(coordinates[1]);
+ }
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index bcdb118..d25ffce 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -37,6 +37,8 @@
import com.android.internal.R;
import com.android.server.UiThread;
+import java.io.PrintWriter;
+
/**
* Autofill Save Prompt
*/
@@ -96,6 +98,9 @@
private final @NonNull OneTimeListener mListener;
+ private final CharSequence mTitle;
+ private final CharSequence mSubTitle;
+
private boolean mDestroyed;
SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@@ -126,37 +131,36 @@
types.add(context.getString(R.string.autofill_save_type_email_address));
}
- final CharSequence title;
switch (types.size()) {
case 1:
- title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
+ mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
types.valueAt(0), providerLabel), 0);
break;
case 2:
- title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types,
+ mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types,
types.valueAt(0), types.valueAt(1), providerLabel), 0);
break;
case 3:
- title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types,
+ mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types,
types.valueAt(0), types.valueAt(1), types.valueAt(2), providerLabel), 0);
break;
default:
// Use generic if more than 3 or invalid type (size 0).
- title = Html.fromHtml(
+ mTitle = Html.fromHtml(
context.getString(R.string.autofill_save_title, providerLabel), 0);
}
- titleView.setText(title);
- final CharSequence subTitle = info.getDescription();
- if (subTitle != null) {
+ titleView.setText(mTitle);
+ mSubTitle = info.getDescription();
+ if (mSubTitle != null) {
final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle);
- subTitleView.setText(subTitle);
+ subTitleView.setText(mSubTitle);
subTitleView.setVisibility(View.VISIBLE);
}
- Slog.i(TAG, "Showing save dialog: " + title);
+ Slog.i(TAG, "Showing save dialog: " + mTitle);
if (sDebug) {
- Slog.d(TAG, "SubTitle: " + subTitle);
+ Slog.d(TAG, "SubTitle: " + mSubTitle);
}
final TextView noButton = view.findViewById(R.id.autofill_save_no);
@@ -207,4 +211,18 @@
throw new IllegalStateException("cannot interact with a destroyed instance");
}
}
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("title: "); pw.println(mTitle);
+ pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
+
+ final View view = mDialog.getWindow().getDecorView();
+ final int[] loc = view.getLocationOnScreen();
+ pw.print(prefix); pw.print("coordinates: ");
+ pw.print('('); pw.print(loc[0]); pw.print(','); pw.print(loc[1]);pw.print(')');
+ pw.print('(');
+ pw.print(loc[0] + view.getWidth()); pw.print(',');
+ pw.print(loc[1] + view.getHeight());pw.println(')');
+ pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+ }
}
diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java
index 6ec74e1..f797517 100644
--- a/services/core/java/com/android/server/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/SyntheticPasswordManager.java
@@ -346,11 +346,14 @@
PasswordData pwd = PasswordData.create(credentialType);
byte[] pwdToken = computePasswordToken(credential, pwd);
+ // In case GK enrollment leaves persistent state around (in RPMB), this will nuke them
+ // to prevent them from accumulating and causing problems.
+ gatekeeper.clearSecureUserId(fakeUid(userId));
GateKeeperResponse response = gatekeeper.enroll(fakeUid(userId), null, null,
passwordTokenToGkInput(pwdToken));
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
Log.e(TAG, "Fail to enroll user password when creating SP for user " + userId);
- return 0;
+ return DEFAULT_HANDLE;
}
pwd.passwordHandle = response.getPayload();
long sid = sidFromPasswordHandle(pwd.passwordHandle);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a5615a9..1ed46a0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -622,6 +622,17 @@
!= ActivityManager.APP_START_MODE_NORMAL) {
if (stopping == null) {
stopping = new ArrayList<>();
+ String compName = service.name.flattenToShortString();
+ EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
+ StringBuilder sb = new StringBuilder(64);
+ sb.append("Stopping service due to app idle: ");
+ UserHandle.formatUid(sb, service.appInfo.uid);
+ sb.append(" ");
+ TimeUtils.formatDuration(service.createTime
+ - SystemClock.elapsedRealtime(), sb);
+ sb.append(" ");
+ sb.append(compName);
+ Slog.w(TAG, sb.toString());
stopping.add(service);
}
}
@@ -1364,7 +1375,7 @@
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
|| s.app.treatLikeActivity, b.client);
- mAm.updateOomAdjLocked(s.app);
+ mAm.updateOomAdjLocked(s.app, true);
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
@@ -1479,13 +1490,15 @@
r.binding.service.app.hasClientActivities
|| r.binding.service.app.treatLikeActivity, null);
}
- mAm.updateOomAdjLocked(r.binding.service.app);
+ mAm.updateOomAdjLocked(r.binding.service.app, false);
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
+ mAm.updateOomAdjLocked();
+
return true;
}
@@ -2225,7 +2238,7 @@
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
- mAm.updateOomAdjLocked(r.app);
+ mAm.updateOomAdjLocked(r.app, true);
}
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
@@ -2349,7 +2362,7 @@
if (ibr.hasBound) {
try {
bumpServiceExecutingLocked(r, false, "bring down unbind");
- mAm.updateOomAdjLocked(r.app);
+ mAm.updateOomAdjLocked(r.app, true);
ibr.hasBound = false;
ibr.requested = false;
r.app.thread.scheduleUnbindService(r,
@@ -2441,7 +2454,7 @@
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
- mAm.updateOomAdjLocked(r.app);
+ mAm.updateOomAdjLocked(r.app, true);
r.app.thread.scheduleStopService(r);
} catch (Exception e) {
Slog.w(TAG, "Exception when destroying service "
@@ -2542,7 +2555,7 @@
// it to go down there and we want it to start out near the top.
mAm.updateLruProcessLocked(s.app, false, null);
}
- mAm.updateOomAdjLocked(s.app);
+ mAm.updateOomAdjLocked(s.app, true);
b.intent.hasBound = false;
// Assume the client doesn't want to know about a rebind;
// we will deal with that later if it asks for one.
@@ -2695,7 +2708,7 @@
mDestroyingServices.remove(r);
r.bindings.clear();
}
- mAm.updateOomAdjLocked(r.app);
+ mAm.updateOomAdjLocked(r.app, true);
}
r.executeFg = false;
if (r.tracker != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ba48783..268adc5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -812,15 +812,28 @@
final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
/**
- * All of the processes that have been forced to be foreground. The key
+ * All of the processes that have been forced to be important. The key
* is the pid of the caller who requested it (we hold a death
* link on it).
*/
- abstract class ForegroundToken implements IBinder.DeathRecipient {
- int pid;
- IBinder token;
+ abstract class ImportanceToken implements IBinder.DeathRecipient {
+ final int pid;
+ final IBinder token;
+ final String reason;
+
+ ImportanceToken(int _pid, IBinder _token, String _reason) {
+ pid = _pid;
+ token = _token;
+ reason = _reason;
+ }
+
+ @Override
+ public String toString() {
+ return "ImportanceToken { " + Integer.toHexString(System.identityHashCode(this))
+ + " " + reason + " " + pid + " " + token + " }";
+ }
}
- final SparseArray<ForegroundToken> mForegroundProcesses = new SparseArray<ForegroundToken>();
+ final SparseArray<ImportanceToken> mImportantProcesses = new SparseArray<ImportanceToken>();
/**
* List of records for processes that someone had tried to start before the
@@ -6499,6 +6512,7 @@
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"No more processes in " + old.uidRecord);
enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
+ EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
}
@@ -6530,6 +6544,7 @@
}
uidRec.updateHasInternetPermission();
mActiveUids.put(proc.uid, uidRec);
+ EventLogTags.writeAmUidRunning(uidRec.uid);
noteUidProcessState(uidRec.uid, uidRec.curProcState);
enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
@@ -6717,7 +6732,7 @@
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- app.forcingToForeground = null;
+ app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
@@ -6845,6 +6860,7 @@
}
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
+ mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
@@ -7716,20 +7732,20 @@
}
}
- void foregroundTokenDied(ForegroundToken token) {
+ void importanceTokenDied(ImportanceToken token) {
synchronized (ActivityManagerService.this) {
synchronized (mPidsSelfLocked) {
- ForegroundToken cur
- = mForegroundProcesses.get(token.pid);
+ ImportanceToken cur
+ = mImportantProcesses.get(token.pid);
if (cur != token) {
return;
}
- mForegroundProcesses.remove(token.pid);
+ mImportantProcesses.remove(token.pid);
ProcessRecord pr = mPidsSelfLocked.get(token.pid);
if (pr == null) {
return;
}
- pr.forcingToForeground = null;
+ pr.forcingToImportant = null;
updateProcessForegroundLocked(pr, false, false);
}
updateOomAdjLocked();
@@ -7737,9 +7753,9 @@
}
@Override
- public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
+ public void setProcessImportant(IBinder token, int pid, boolean isForeground, String reason) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
- "setProcessForeground()");
+ "setProcessImportant()");
synchronized(this) {
boolean changed = false;
@@ -7749,28 +7765,26 @@
Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
return;
}
- ForegroundToken oldToken = mForegroundProcesses.get(pid);
+ ImportanceToken oldToken = mImportantProcesses.get(pid);
if (oldToken != null) {
oldToken.token.unlinkToDeath(oldToken, 0);
- mForegroundProcesses.remove(pid);
+ mImportantProcesses.remove(pid);
if (pr != null) {
- pr.forcingToForeground = null;
+ pr.forcingToImportant = null;
}
changed = true;
}
if (isForeground && token != null) {
- ForegroundToken newToken = new ForegroundToken() {
+ ImportanceToken newToken = new ImportanceToken(pid, token, reason) {
@Override
public void binderDied() {
- foregroundTokenDied(this);
+ importanceTokenDied(this);
}
};
- newToken.pid = pid;
- newToken.token = token;
try {
token.linkToDeath(newToken, 0);
- mForegroundProcesses.put(pid, newToken);
- pr.forcingToForeground = token;
+ mImportantProcesses.put(pid, newToken);
+ pr.forcingToImportant = newToken;
changed = true;
} catch (RemoteException e) {
// If the process died while doing this, we will later
@@ -11312,7 +11326,7 @@
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.verifiedAdj;
- boolean success = updateOomAdjLocked(cpr.proc);
+ boolean success = updateOomAdjLocked(cpr.proc, true);
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
@@ -11774,7 +11788,7 @@
dst.proc = r;
dst.notifyAll();
}
- updateOomAdjLocked(r);
+ updateOomAdjLocked(r, true);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
@@ -13505,7 +13519,7 @@
}
}
if (changed) {
- updateOomAdjLocked(pr);
+ updateOomAdjLocked(pr, true);
}
}
} finally {
@@ -15489,12 +15503,12 @@
}
}
- if (mForegroundProcesses.size() > 0) {
+ if (mImportantProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
boolean printed = false;
- for (int i=0; i<mForegroundProcesses.size(); i++) {
+ for (int i = 0; i< mImportantProcesses.size(); i++) {
ProcessRecord r = mPidsSelfLocked.get(
- mForegroundProcesses.valueAt(i).pid);
+ mImportantProcesses.valueAt(i).pid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
@@ -15506,8 +15520,8 @@
printed = true;
printedAnything = true;
}
- pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
- pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
+ pw.print(" PID #"); pw.print(mImportantProcesses.keyAt(i));
+ pw.print(": "); pw.println(mImportantProcesses.valueAt(i));
}
}
}
@@ -17778,7 +17792,7 @@
app.unlinkDeathRecipient();
app.makeInactive(mProcessStats);
app.waitingToKill = null;
- app.forcingToForeground = null;
+ app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.foregroundActivities = false;
app.hasShownUi = false;
@@ -18278,7 +18292,7 @@
mBackupAppName = app.packageName;
// Try not to kill the process during backup
- updateOomAdjLocked(proc);
+ updateOomAdjLocked(proc, true);
// If the process is already attached, schedule the creation of the backup agent now.
// If it is not yet live, this will be done when it attaches to the framework.
@@ -18375,7 +18389,7 @@
// Not backing this app up any more; reset its OOM adjustment
final ProcessRecord proc = mBackupTarget.app;
- updateOomAdjLocked(proc);
+ updateOomAdjLocked(proc, true);
proc.inFullBackup = false;
oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
@@ -20773,14 +20787,6 @@
app.cached = false;
app.adjType = "fg-service";
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- } else if (app.forcingToForeground != null) {
- // The user is aware of this app, so make it visible.
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- app.cached = false;
- app.adjType = "force-fg";
- app.adjSource = app.forcingToForeground;
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
} else if (app.hasOverlayUi) {
// The process is display an overlay UI.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -20791,6 +20797,21 @@
}
}
+ if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+ || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ if (app.forcingToImportant != null) {
+ // This is currently used for toasts... they are not interactive, and
+ // we don't want them to cause the app to become fully foreground (and
+ // thus out of background check), so we yes the best background level we can.
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+ app.cached = false;
+ app.adjType = "force-imp";
+ app.adjSource = app.forcingToImportant;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ }
+ }
+
if (app == mHeavyWeightProcess) {
if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
// We don't want to kill the current heavy-weight process.
@@ -22031,10 +22052,7 @@
+ mConstants.SERVICE_USAGE_INTERACTION_TIME;
}
} else {
- // If the app was being forced to the foreground, by say a Toast, then
- // no need to treat it as an interaction
- isInteraction = app.forcingToForeground == null
- && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.fgInteractionTime = 0;
}
if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
@@ -22135,7 +22153,14 @@
return act;
}
- final boolean updateOomAdjLocked(ProcessRecord app) {
+ /**
+ * Update OomAdj for a specific process.
+ * @param app The process to update
+ * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
+ * if necessary, or skip.
+ * @return whether updateOomAdjLocked(app) was successful.
+ */
+ final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final boolean wasCached = app.cached;
@@ -22150,7 +22175,8 @@
? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());
- if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
+ if (oomAdjAll
+ && (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ)) {
// Changed to/from cached state, so apps after it in the LRU
// list may also be changed.
updateOomAdjLocked();
@@ -22564,6 +22590,7 @@
} else {
if (uidRec.idle) {
uidChange = UidRecord.CHANGE_ACTIVE;
+ EventLogTags.writeAmUidActive(uidRec.uid);
uidRec.idle = false;
}
uidRec.lastBackgroundTime = 0;
@@ -22642,6 +22669,7 @@
if (UserHandle.getAppId(uidRec.uid) == appId) {
if (userId == UserHandle.USER_ALL ||
userId == UserHandle.getUserId(uidRec.uid)) {
+ EventLogTags.writeAmUidIdle(uidRec.uid);
uidRec.idle = true;
Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
+ " from package " + packageName + " user " + userId);
@@ -22676,6 +22704,7 @@
final long bgTime = uidRec.lastBackgroundTime;
if (bgTime > 0 && !uidRec.idle) {
if (bgTime <= maxBgTime) {
+ EventLogTags.writeAmUidIdle(uidRec.uid);
uidRec.idle = true;
doStopUidLocked(uidRec.uid, uidRec);
} else {
@@ -23728,7 +23757,7 @@
}
pr.hasOverlayUi = hasOverlayUi;
//Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
- updateOomAdjLocked(pr);
+ updateOomAdjLocked(pr, true);
}
}
@@ -23866,6 +23895,34 @@
}
}
+ public void waitForBroadcastIdle(PrintWriter pw) {
+ enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
+ while (true) {
+ boolean idle = true;
+ synchronized (this) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ if (!queue.isIdle()) {
+ final String msg = "Waiting for queue " + queue + " to become idle...";
+ pw.println(msg);
+ pw.flush();
+ Slog.v(TAG, msg);
+ idle = false;
+ }
+ }
+ }
+
+ if (idle) {
+ final String msg = "All broadcast queues are idle!";
+ pw.println(msg);
+ pw.flush();
+ Slog.v(TAG, msg);
+ return;
+ } else {
+ SystemClock.sleep(1000);
+ }
+ }
+ }
+
/**
* Return the user id of the last resumed activity.
*/
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b6bfb00..dab122f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -251,6 +251,8 @@
return runUpdateApplicationInfo(pw);
case "no-home-screen":
return runNoHomeScreen(pw);
+ case "wait-for-broadcast-idle":
+ return runWaitForBroadcastIdle(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -2419,6 +2421,11 @@
return 0;
}
+ int runWaitForBroadcastIdle(PrintWriter pw) throws RemoteException {
+ mInternal.waitForBroadcastIdle(pw);
+ return 0;
+ }
+
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
Configuration config = mInterface.getConfiguration();
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index d4de521..bf7b663 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -10,6 +10,7 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
@@ -78,7 +79,8 @@
private int startResult;
private boolean currentTransitionProcessRunning;
private int windowsDrawnDelayMs;
- private int startingWindowDelayMs;
+ private int startingWindowDelayMs = -1;
+ private int bindApplicationDelayMs = -1;
private int reason = APP_TRANSITION_TIMEOUT;
private boolean loggedWindowsDrawn;
private boolean loggedStartingWindowDrawn;
@@ -296,6 +298,22 @@
}
}
+ /**
+ * Notifies the tracker that we called immediately before we call bindApplication on the client.
+ *
+ * @param app The client into which we'll call bindApplication.
+ */
+ void notifyBindApplication(ProcessRecord app) {
+ for (int i = mStackTransitionInfo.size() - 1; i >= 0; i--) {
+ final StackTransitionInfo info = mStackTransitionInfo.valueAt(i);
+
+ // App isn't attached to record yet, so match with info.
+ if (info.launchedActivity.appInfo == app.info) {
+ info.bindApplicationDelayMs = calculateCurrentDelay();
+ }
+ }
+ }
+
private boolean allStacksWindowsDrawn() {
for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
if (!mStackTransitionInfo.valueAt(index).loggedWindowsDrawn) {
@@ -356,6 +374,10 @@
builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
info.startingWindowDelayMs);
}
+ if (info.bindApplicationDelayMs != -1) {
+ builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
+ info.bindApplicationDelayMs);
+ }
builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
mMetricsLogger.write(builder);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d348224..c5d5867 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -232,7 +232,7 @@
static final int STACK_VISIBLE = 1;
// Stack is considered visible, but only becuase it has activity that is visible behind other
// activities and there is a specific combination of stacks.
- private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
+ static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
@VisibleForTesting
/* The various modes for the method {@link #removeTask}. */
@@ -1652,7 +1652,7 @@
if (StackId.isBackdropToTranslucentActivity(mStackId)
&& hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(topStackId)
- && !topStack.topActivity().fullscreen) {
+ && (topStack.topActivity() == null || !topStack.topActivity().fullscreen)) {
// The fullscreen or assistant stack should be visible if it has a visible behind
// activity behind the home or recents stack that is translucent.
return STACK_VISIBLE_ACTIVITY_BEHIND;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6d6f33d..e33ae0d 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -577,7 +577,7 @@
}
boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null);
if (startedActivityStackId == PINNED_STACK_ID && (result == START_TASK_TO_FRONT
|| result == START_DELIVERED_TO_TOP || clearedTask)) {
// The activity was already running in the pinned stack so it wasn't started, but either
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index d08298b..639b7a9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -51,7 +51,6 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.TimeUtils;
-import com.android.server.DeviceIdleController;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -204,6 +203,11 @@
mDelayBehindServices = allowDelayBehindServices;
}
+ @Override
+ public String toString() {
+ return mQueueName;
+ }
+
public boolean isPendingBroadcastProcessLocked(int pid) {
return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
}
@@ -682,7 +686,7 @@
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceivers.add(r);
- mService.updateOomAdjLocked(r.curApp);
+ mService.updateOomAdjLocked(r.curApp, true);
}
}
try {
@@ -1579,6 +1583,11 @@
record.intent == null ? "" : record.intent.getAction());
}
+ final boolean isIdle() {
+ return mParallelBroadcasts.isEmpty() && mOrderedBroadcasts.isEmpty()
+ && (mPendingBroadcast == null);
+ }
+
final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index f618fc7..372ab6b 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -114,3 +114,14 @@
# UserState has changed
30051 am_user_state_changed (id|1|5),(state|1|5)
+
+# Note when any processes of a uid have started running
+30052 am_uid_running (UID|1|5)
+# Note when all processes of a uid have stopped.
+30053 am_uid_stopped (UID|1|5)
+# Note when the state of a uid has become active.
+30054 am_uid_active (UID|1|5)
+# Note when the state of a uid has become idle (background check enforced).
+30055 am_uid_idle (UID|1|5)
+# Note when a service is being forcibly stopped because its app went idle.
+30056 am_stop_idle_service (UID|1|5),(Component Name|3)
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index fbc2bd2..b222e3a 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -135,7 +135,7 @@
long interactionEventTime; // The time we sent the last interaction event
long fgInteractionTime; // When we became foreground for interaction purposes
String waitingToKill; // Process is waiting to be killed when in the bg, and reason
- IBinder forcingToForeground;// Token that is forcing this process to be foreground
+ Object forcingToImportant; // Token that is forcing this process to be important
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
int lruSeq; // Sequence id for identifying LRU update cycles
CompatibilityInfo compat; // last used compatibility mode
@@ -302,9 +302,9 @@
pw.print(" hasAboveClient="); pw.print(hasAboveClient);
pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
}
- if (foregroundServices || forcingToForeground != null) {
+ if (foregroundServices || forcingToImportant != null) {
pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices);
- pw.print(" forcingToForeground="); pw.println(forcingToForeground);
+ pw.print(" forcingToImportant="); pw.println(forcingToImportant);
}
if (reportedInteraction || fgInteractionTime != 0) {
pw.print(prefix); pw.print("reportedInteraction=");
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 93a22494..125095c 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -310,7 +310,6 @@
*/
void handleFocusGain(int focusGain) {
try {
- final int oldLoss = mFocusLossReceived;
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -322,10 +321,9 @@
}
if (mFocusLossWasNotified) {
fd.dispatchAudioFocusChange(focusGain, mClientId);
- } else if (oldLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
- mFocusController.unduckPlayers(this);
}
}
+ mFocusController.unduckPlayers(this);
mFocusLossWasNotified = false;
} catch (android.os.RemoteException e) {
Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
@@ -335,6 +333,15 @@
/**
* Called synchronized on MediaFocusControl.mAudioFocusLock
*/
+ void handleFocusGainFromRequest(int focusRequestResult) {
+ if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ mFocusController.unduckPlayers(this);
+ }
+ }
+
+ /**
+ * Called synchronized on MediaFocusControl.mAudioFocusLock
+ */
void handleFocusLoss(int focusLoss, @Nullable final FocusRequester fr) {
try {
if (focusLoss != mFocusLossReceived) {
@@ -383,6 +390,8 @@
Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
+ " to " + mClientId + ", ducking implemented by framework");
}
+ mFocusController.notifyExtPolicyFocusLoss_syncAf(
+ toAudioFocusInfo(), false /* wasDispatched */);
return; // with mFocusLossWasNotified = false
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index f5c13c1..7d742ff 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -752,6 +752,7 @@
// push focus requester at the top of the audio focus stack
mFocusStack.push(nfr);
+ nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
}
notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1d843c1..70766f9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2871,8 +2871,7 @@
adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
System.currentTimeMillis());
summaryRecord = new NotificationRecord(getContext(), summarySbn,
- notificationRecord.getChannel(), mRankingHelper.supportsChannels(
- summarySbn.getPackageName(), summarySbn.getUid()));
+ notificationRecord.getChannel());
summaries.put(pkg, summarySbn.getKey());
}
}
@@ -3211,8 +3210,7 @@
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, notificationUid, callingPid, notification,
user, null, System.currentTimeMillis());
- final NotificationRecord r = new NotificationRecord(getContext(), n, channel,
- mRankingHelper.supportsChannels(pkg, notificationUid));
+ final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
return;
@@ -3937,7 +3935,7 @@
}
}
try {
- mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+ mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
} catch (RemoteException e) {
// Shouldn't happen.
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f019a5c..5a5e658 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -116,7 +116,7 @@
private int mSuppressedVisualEffects = 0;
private String mUserExplanation;
private String mPeopleExplanation;
- private boolean mSupportsChannels = false;
+ private boolean mPreChannelsNotification = true;
private Uri mSound;
private long[] mVibration;
private AudioAttributes mAttributes;
@@ -129,7 +129,7 @@
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
- NotificationChannel channel, boolean supportsChannels)
+ NotificationChannel channel)
{
this.sbn = sbn;
mOriginalFlags = sbn.getNotification().flags;
@@ -139,7 +139,7 @@
mContext = context;
stats = new NotificationUsageStats.SingleNotificationStats();
mChannel = channel;
- mSupportsChannels = supportsChannels;
+ mPreChannelsNotification = isPreChannelsNotification();
mSound = calculateSound();
mVibration = calculateVibration();
mAttributes = calculateAttributes();
@@ -147,11 +147,27 @@
mLight = calculateLights();
}
+ private boolean isPreChannelsNotification() {
+ try {
+ if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
+ final ApplicationInfo applicationInfo =
+ mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
+ 0, UserHandle.getUserId(sbn.getUid()));
+ if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+ return true;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Can't find package", e);
+ }
+ return false;
+ }
+
private Uri calculateSound() {
final Notification n = sbn.getNotification();
Uri sound = mChannel.getSound();
- if (!mSupportsChannels && (getChannel().getUserLockedFields()
+ if (mPreChannelsNotification && (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_SOUND) == 0) {
final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
@@ -176,7 +192,7 @@
: defaultLightColor;
Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
defaultLightOn, defaultLightOff) : null;
- if (!mSupportsChannels
+ if (mPreChannelsNotification
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
final Notification notification = sbn.getNotification();
@@ -207,7 +223,7 @@
} else {
vibration = null;
}
- if (!mSupportsChannels
+ if (mPreChannelsNotification
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
final Notification notification = sbn.getNotification();
@@ -229,7 +245,7 @@
attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
}
- if (!mSupportsChannels
+ if (mPreChannelsNotification
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_SOUND) == 0) {
if (n.audioAttributes != null) {
@@ -278,7 +294,7 @@
stats.requestedImportance = requestedImportance;
stats.isNoisy = mSound != null || mVibration != null;
- if (!mSupportsChannels
+ if (mPreChannelsNotification
&& (importance == IMPORTANCE_UNSPECIFIED
|| (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
@@ -445,7 +461,7 @@
pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
- if (!mSupportsChannels) {
+ if (mPreChannelsNotification) {
pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
notification.defaults, notification.flags));
pw.println(prefix + "n.sound=" + notification.sound);
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 14d796f..4d19b52 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -42,6 +42,4 @@
void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannels(String pkg, int uid);
ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted);
-
- boolean supportsChannels(String pkg, int uid);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 1e741de..7758516 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -273,14 +273,8 @@
}
private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
- if (supportsChannels(r)) {
- return false;
- }
-
final int userId = UserHandle.getUserId(r.uid);
- final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg,
- PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- userId);
+ final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
// O apps should not have the default channel.
return false;
@@ -506,31 +500,6 @@
}
@Override
- public boolean supportsChannels(String pkg, int uid) {
- Record r = getOrCreateRecord(pkg, uid);
-
- if (r == null) {
- return false;
- }
-
- if (r.channels.size() == 1
- && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- return false;
- }
-
- return true;
- }
-
- private boolean supportsChannels(Record r) {
- if (r.channels.size() == 1
- && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- return false;
- }
-
- return (r.channels.size() > 0);
- }
-
- @Override
public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromTargetApp) {
Preconditions.checkNotNull(pkg);
@@ -602,10 +571,6 @@
r.channels.put(channel.getId(), channel);
MetricsLogger.action(getChannelLog(channel, pkg).setType(
MetricsProto.MetricsEvent.TYPE_OPEN));
-
- // Remove Default Channel.
- r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
-
updateConfig();
}
@@ -702,7 +667,13 @@
if (r == null) {
return;
}
- r.channels.clear();
+ int N = r.channels.size() - 1;
+ for (int i = N; i >= 0; i--) {
+ String key = r.channels.keyAt(i);
+ if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
+ r.channels.remove(key);
+ }
+ }
updateConfig();
}
@@ -1066,8 +1037,6 @@
final int uid = uidList[i];
synchronized (mRecords) {
mRecords.remove(recordKey(pkg, uid));
- // reset to default settings and re-add misc channel for pre-O apps
- getOrCreateRecord(pkg, uid);
}
mRestoredWithoutUids.remove(pkg);
updated = true;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 78d931f..0173533 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6557,7 +6557,7 @@
// the instant application, we'll do the right thing.
final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
auxiliaryResponse = new AuxiliaryResolveInfo(
- ai.packageName, null /*splitName*/, ai.versionCode);
+ ai.packageName, null /*splitName*/, ai.versionCode, null /*failureIntent*/);
}
}
if (auxiliaryResponse != null) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index bed8f1a..7f0528a 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1611,6 +1611,11 @@
*/
private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
boolean forPinRequest) {
+ if (shortcut.isReturnedByServer()) {
+ Log.w(TAG,
+ "Re-publishing ShortcutInfo returned by server is not supported."
+ + " Some information such as icon may lost from shortcut.");
+ }
Preconditions.checkNotNull(shortcut, "Null shortcut detected");
if (shortcut.getActivity() != null) {
Preconditions.checkState(
@@ -1670,6 +1675,13 @@
}
}
+ private List<ShortcutInfo> setReturnedByServer(List<ShortcutInfo> shortcuts) {
+ for (int i = shortcuts.size() - 1; i >= 0; i--) {
+ shortcuts.get(i).setReturnedByServer();
+ }
+ return shortcuts;
+ }
+
// === APIs ===
@Override
@@ -2049,7 +2061,7 @@
final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.findAll(ret, query, cloneFlags);
- return new ParceledListSlice<>(ret);
+ return new ParceledListSlice<>(setReturnedByServer(ret));
}
@Override
@@ -2406,7 +2418,7 @@
});
}
}
- return ret;
+ return setReturnedByServer(ret);
}
private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
diff --git a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
index 4035ade..9a08ac3 100644
--- a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
+++ b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
@@ -73,13 +73,13 @@
final int userId = UserHandle.myUserId();
UserEnvironment environment = new UserEnvironment(userId);
LogRunnable task = new LogRunnable();
- task.setRootDirectory(environment.getExternalStorageDirectory());
task.setDownloadsDirectory(
environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
task.setSystemSize(FileCollector.getSystemSize(this));
task.setLogOutputFile(new File(DUMPSYS_CACHE_PATH));
task.setAppCollector(collector);
task.setJobService(this, params);
+ task.setContext(this);
AsyncTask.execute(task);
return true;
}
@@ -106,7 +106,8 @@
}
private static boolean isCharging(Context context) {
- BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
+ BatteryManager batteryManager =
+ (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
if (batteryManager != null) {
return batteryManager.isCharging();
}
@@ -127,14 +128,10 @@
private JobParameters mParams;
private AppCollector mCollector;
private File mOutputFile;
- private File mRootDirectory;
private File mDownloadsDirectory;
+ private Context mContext;
private long mSystemSize;
- public void setRootDirectory(File file) {
- mRootDirectory = file;
- }
-
public void setDownloadsDirectory(File file) {
mDownloadsDirectory = file;
}
@@ -151,14 +148,25 @@
mSystemSize = size;
}
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
public void setJobService(JobService jobService, JobParameters params) {
mJobService = jobService;
mParams = params;
}
public void run() {
- FileCollector.MeasurementResult mainCategories =
- FileCollector.getMeasurementResult(mRootDirectory);
+ FileCollector.MeasurementResult mainCategories;
+ try {
+ mainCategories = FileCollector.getMeasurementResult(mContext);
+ } catch (IllegalStateException e) {
+ // This can occur if installd has an issue.
+ Log.e(TAG, "Error while measuring storage", e);
+ finishJob(true);
+ return;
+ }
FileCollector.MeasurementResult downloads =
FileCollector.getMeasurementResult(mDownloadsDirectory);
@@ -168,12 +176,10 @@
needsReschedule = false;
logToFile(mainCategories, downloads, stats, mSystemSize);
} else {
- Log.w("TAG", "Timed out while fetching package stats.");
+ Log.w(TAG, "Timed out while fetching package stats.");
}
- if (mJobService != null) {
- mJobService.jobFinished(mParams, needsReschedule);
- }
+ finishJob(needsReschedule);
}
private void logToFile(MeasurementResult mainCategories, MeasurementResult downloads,
@@ -187,5 +193,11 @@
Log.e(TAG, "Exception while writing opportunistic disk file cache.", e);
}
}
+
+ private void finishJob(boolean needsReschedule) {
+ if (mJobService != null) {
+ mJobService.jobFinished(mParams, needsReschedule);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/storage/FileCollector.java b/services/core/java/com/android/server/storage/FileCollector.java
index 90f9f139..0c119a7 100644
--- a/services/core/java/com/android/server/storage/FileCollector.java
+++ b/services/core/java/com/android/server/storage/FileCollector.java
@@ -17,13 +17,17 @@
package com.android.server.storage;
import android.annotation.IntDef;
+import android.app.usage.ExternalStorageStats;
+import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.ArrayMap;
import java.io.File;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
@@ -154,15 +158,46 @@
}
/**
+ * Returns the file categorization result for the primary internal storage UUID.
+ *
+ * @param context
+ */
+ public static MeasurementResult getMeasurementResult(Context context) {
+ MeasurementResult result = new MeasurementResult();
+ StorageStatsManager ssm =
+ (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
+ ExternalStorageStats stats = null;
+ try {
+ stats =
+ ssm.queryExternalStatsForUser(
+ StorageManager.UUID_PRIVATE_INTERNAL,
+ UserHandle.of(context.getUserId()));
+ result.imagesSize = stats.getImageBytes();
+ result.videosSize = stats.getVideoBytes();
+ result.audioSize = stats.getAudioBytes();
+ result.miscSize =
+ stats.getTotalBytes()
+ - result.imagesSize
+ - result.videosSize
+ - result.audioSize;
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not query storage");
+ }
+
+ return result;
+ }
+
+ /**
* Returns the size of a system for a given context. This is done by finding the difference
* between the shared data and the total primary storage size.
+ *
* @param context Context to use to get storage information.
*/
public static long getSystemSize(Context context) {
PackageManager pm = context.getPackageManager();
VolumeInfo primaryVolume = pm.getPrimaryStorageCurrentVolume();
- StorageManager sm = context.getSystemService(StorageManager.class);
+ StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
VolumeInfo shared = sm.findEmulatedForPrivate(primaryVolume);
if (shared == null) {
return 0;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7a36da2..a38addb 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -54,6 +54,7 @@
import android.graphics.Bitmap;
import android.graphics.Path;
import android.graphics.Rect;
+import android.os.Binder;
import android.os.Debug;
import android.os.IBinder;
import android.os.IRemoteCallback;
@@ -1808,27 +1809,25 @@
final IAppTransitionAnimationSpecsFuture future
= mNextAppTransitionAnimationsSpecsFuture;
mNextAppTransitionAnimationsSpecsFuture = null;
- mDefaultExecutor.execute(new Runnable() {
- @Override
- public void run() {
- AppTransitionAnimationSpec[] specs = null;
- try {
- specs = future.get();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to fetch app transition specs: " + e);
- }
- synchronized (mService.mWindowMap) {
- mNextAppTransitionAnimationsSpecsPending = false;
- overridePendingAppTransitionMultiThumb(specs,
- mNextAppTransitionFutureCallback, null /* finishedCallback */,
- mNextAppTransitionScaleUp);
- mNextAppTransitionFutureCallback = null;
- if (specs != null) {
- mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
- }
- }
- mService.requestTraversal();
+ mDefaultExecutor.execute(() -> {
+ AppTransitionAnimationSpec[] specs = null;
+ try {
+ Binder.allowBlocking(future.asBinder());
+ specs = future.get();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to fetch app transition specs: " + e);
}
+ synchronized (mService.mWindowMap) {
+ mNextAppTransitionAnimationsSpecsPending = false;
+ overridePendingAppTransitionMultiThumb(specs,
+ mNextAppTransitionFutureCallback, null /* finishedCallback */,
+ mNextAppTransitionScaleUp);
+ mNextAppTransitionFutureCallback = null;
+ if (specs != null) {
+ mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
+ }
+ }
+ mService.requestTraversal();
});
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b27d6c4..92d26cb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2948,27 +2948,29 @@
}
// Don't include wallpaper in bounds calculation
- if (!mutableIncludeFullDisplay.value && includeDecor) {
- final TaskStack stack = w.getStack();
- if (stack != null) {
- stack.getBounds(frame);
- }
+ if (!w.mIsWallpaper && !mutableIncludeFullDisplay.value) {
+ if (includeDecor) {
+ final TaskStack stack = w.getStack();
+ if (stack != null) {
+ stack.getBounds(frame);
+ }
- // We want to screenshot with the exact bounds of the surface of the app. Thus,
- // intersect it with the frame.
- frame.intersect(w.mFrame);
- }else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
- final Rect wf = w.mFrame;
- final Rect cr = w.mContentInsets;
- int left = wf.left + cr.left;
- int top = wf.top + cr.top;
- int right = wf.right - cr.right;
- int bottom = wf.bottom - cr.bottom;
- frame.union(left, top, right, bottom);
- w.getVisibleBounds(stackBounds);
- if (!Rect.intersects(frame, stackBounds)) {
- // Set frame empty if there's no intersection.
- frame.setEmpty();
+ // We want to screenshot with the exact bounds of the surface of the app. Thus,
+ // intersect it with the frame.
+ frame.intersect(w.mFrame);
+ } else {
+ final Rect wf = w.mFrame;
+ final Rect cr = w.mContentInsets;
+ int left = wf.left + cr.left;
+ int top = wf.top + cr.top;
+ int right = wf.right - cr.right;
+ int bottom = wf.bottom - cr.bottom;
+ frame.union(left, top, right, bottom);
+ w.getVisibleBounds(stackBounds);
+ if (!Rect.intersects(frame, stackBounds)) {
+ // Set frame empty if there's no intersection.
+ frame.setEmpty();
+ }
}
}
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 813dcf5..514e996 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -29,16 +29,46 @@
namespace android {
-using ILight = ::android::hardware::light::V2_0::ILight;
using Brightness = ::android::hardware::light::V2_0::Brightness;
using Flash = ::android::hardware::light::V2_0::Flash;
-using Type = ::android::hardware::light::V2_0::Type;
+using ILight = ::android::hardware::light::V2_0::ILight;
using LightState = ::android::hardware::light::V2_0::LightState;
using Status = ::android::hardware::light::V2_0::Status;
+using Type = ::android::hardware::light::V2_0::Type;
template<typename T>
using Return = ::android::hardware::Return<T>;
-static sp<ILight> gLight;
+class LightHal {
+private:
+ static sp<ILight> sLight;
+ static bool sLightInit;
+
+ LightHal() {}
+
+public:
+ static void disassociate() {
+ sLightInit = false;
+ sLight = nullptr;
+ }
+
+ static sp<ILight> associate() {
+ if ((sLight == nullptr && !sLightInit) ||
+ (sLight != nullptr && !sLight->ping().isOk())) {
+ // will return the hal if it exists the first time.
+ sLight = ILight::getService();
+ sLightInit = true;
+
+ if (sLight == nullptr) {
+ ALOGE("Unable to get ILight interface.");
+ }
+ }
+
+ return sLight;
+ }
+};
+
+sp<ILight> LightHal::sLight = nullptr;
+bool LightHal::sLightInit = false;
static bool validate(jint light, jint flash, jint brightness) {
bool valid = true;
@@ -103,7 +133,7 @@
const LightState &state) {
if (!ret.isOk()) {
ALOGE("Failed to issue set light command.");
- gLight = nullptr;
+ LightHal::disassociate();
return;
}
@@ -137,12 +167,9 @@
return;
}
- if (gLight == nullptr || !gLight->ping().isOk()) {
- gLight = ILight::getService();
- }
+ sp<ILight> hal = LightHal::associate();
- if (gLight == nullptr) {
- ALOGE("Unable to get ILight interface.");
+ if (hal == nullptr) {
return;
}
@@ -152,7 +179,7 @@
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
- Return<Status> ret = gLight->setLight(type, state);
+ Return<Status> ret = hal->setLight(type, state);
processReturn(ret, type, state);
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 2e8b068..0cf4994 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -69,7 +69,7 @@
Notification n = builder.build();
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
return r;
}
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 5e8b3d4..d4904f5 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -259,7 +259,7 @@
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
mService.addNotification(r);
return r;
}
@@ -769,7 +769,7 @@
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
mService.addNotification(r);
mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 33d2d07..24cb72e 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -53,21 +53,21 @@
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
left.setGlobalSortKey("first");
NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
right.setGlobalSortKey("second");
NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
final List<NotificationRecord> expected = new ArrayList<>();
@@ -93,13 +93,13 @@
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
right.setGlobalSortKey("not null");
final List<NotificationRecord> expected = new ArrayList<>();
@@ -124,14 +124,14 @@
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
left.setGlobalSortKey("not null");
NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel(), true);
+ "", 1499), getDefaultChannel());
final List<NotificationRecord> expected = new ArrayList<>();
expected.add(left);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 7a2dbaf..3dbd803 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -71,7 +71,7 @@
Notification n = builder.build();
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
return r;
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index ccd2db0..84945ab 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -108,7 +108,7 @@
.build();
mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "minCall", callUid, callUid, n1,
- new UserHandle(userId), "", 2000), getDefaultChannel(), false);
+ new UserHandle(userId), "", 2000), getDefaultChannel());
mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -118,7 +118,7 @@
.build();
mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "highcall", callUid, callUid, n2,
- new UserHandle(userId), "", 1999), getDefaultChannel(), false);
+ new UserHandle(userId), "", 1999), getDefaultChannel());
mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -128,14 +128,14 @@
.build();
mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
- "", 1499), getDefaultChannel(), false);
+ "", 1499), getDefaultChannel());
mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
- "", 1599), getDefaultChannel(), false);
+ "", 1599), getDefaultChannel());
mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
@@ -143,27 +143,27 @@
.setCategory(Notification.CATEGORY_MESSAGE).build();
mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
- "", 1299), getDefaultChannel(), false);
+ "", 1299), getDefaultChannel());
mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
- "", 1259), getDefaultChannel(), false);
+ "", 1259), getDefaultChannel());
mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
- "", 1259), getDefaultChannel(), false);
+ "", 1259), getDefaultChannel());
mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
- "", 1258), getDefaultChannel(), false);
+ "", 1258), getDefaultChannel());
mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -173,7 +173,7 @@
.build();
mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
- "", 9258), getDefaultChannel(), false);
+ "", 9258), getDefaultChannel());
mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX);
@@ -181,7 +181,7 @@
.setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
- "", 1599), getDefaultChannel(), false);
+ "", 1599), getDefaultChannel());
mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -190,7 +190,7 @@
.build();
mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
- "", 9258), getDefaultChannel(), false);
+ "", 9258), getDefaultChannel());
mRecordCheaterColorized.setUserImportance(NotificationManager.IMPORTANCE_LOW);
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index f3eb4f8..177c02d 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -165,7 +165,7 @@
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
nb.build(), new UserHandle(uid), null, 0);
- return new NotificationRecord(mContext, sbn, channel, true);
+ return new NotificationRecord(mContext, sbn, channel);
}
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
return generateNotificationRecord(channel, null);
@@ -184,7 +184,7 @@
}
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
nb.build(), new UserHandle(uid), null, 0);
- return new NotificationRecord(mContext, sbn, channel, true);
+ return new NotificationRecord(mContext, sbn, channel);
}
@Test
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 66f3799..1c8ca84 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -21,6 +21,7 @@
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -60,10 +61,6 @@
private final Context mMockContext = Mockito.mock(Context.class);
@Mock PackageManager mPm;
- // constants for targetSdk version. N is pre channels, O is post.
- private final boolean N = false;
- private final boolean O = true;
-
private final String pkg = "com.android.server.notification";
private final int uid = 9583;
private final String pkg2 = "pkg2";
@@ -79,6 +76,7 @@
new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
NotificationManager.IMPORTANCE_UNSPECIFIED);
private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+ final ApplicationInfo legacy = new ApplicationInfo();
final ApplicationInfo upgrade = new ApplicationInfo();
private static final long[] CUSTOM_VIBRATION = new long[] {
@@ -102,13 +100,17 @@
InstrumentationRegistry.getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
+ legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
- when(mMockContext.getApplicationInfo()).thenReturn(upgrade);
+ try {
+ when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
+ when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
+ } catch (PackageManager.NameNotFoundException e) {}
}
- private StatusBarNotification getNotification(boolean supportsChannels, boolean noisy,
- boolean defaultSound, boolean buzzy, boolean defaultVibration, boolean lights,
- boolean defaultLights) {
+ private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
+ boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights) {
+ when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
final Builder builder = new Builder(mMockContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -147,13 +149,13 @@
}
builder.setDefaults(defaults);
- if (supportsChannels) {
+ if (!preO) {
builder.setChannelId(channelId);
}
Notification n = builder.build();
- if (!supportsChannels) {
+ if (preO) {
return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n,
mUser, null, uid);
} else {
@@ -170,11 +172,11 @@
public void testSound_default_preUpgradeUsesNotification() throws Exception {
defaultChannel.setSound(null, null);
// pre upgrade, default sound.
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
}
@@ -183,11 +185,11 @@
public void testSound_custom_preUpgradeUsesNotification() throws Exception {
defaultChannel.setSound(null, null);
// pre upgrade, custom sound.
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_SOUND, record.getSound());
assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@@ -197,11 +199,11 @@
defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
// pre upgrade, default sound.
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_SOUND, record.getSound());
assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@@ -209,11 +211,11 @@
@Test
public void testSound_noSound_preUpgrade() throws Exception {
// pre upgrade, default sound.
- StatusBarNotification sbn = getNotification(N, false /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(null, record.getSound());
assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
}
@@ -222,11 +224,11 @@
public void testSound_default_upgradeUsesChannel() throws Exception {
channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
// post upgrade, default sound.
- StatusBarNotification sbn = getNotification(O, true /* noisy */,
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(CUSTOM_SOUND, record.getSound());
assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@@ -235,11 +237,11 @@
public void testVibration_default_preUpgradeUsesNotification() throws Exception {
defaultChannel.enableVibration(false);
// pre upgrade, default vibration.
- StatusBarNotification sbn = getNotification(N, false /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertNotNull(record.getVibration());
}
@@ -247,11 +249,11 @@
public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
defaultChannel.enableVibration(false);
// pre upgrade, custom vibration.
- StatusBarNotification sbn = getNotification(N, false /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_VIBRATION, record.getVibration());
}
@@ -260,11 +262,11 @@
defaultChannel.enableVibration(true);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
// pre upgrade, custom vibration.
- StatusBarNotification sbn = getNotification(N, false /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
}
@@ -272,20 +274,20 @@
public void testVibration_custom_upgradeUsesChannel() throws Exception {
channel.enableVibration(true);
// post upgrade, custom vibration.
- StatusBarNotification sbn = getNotification(O, false /* noisy */,
+ StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
}
@Test
public void testImportance_preUpgrade() throws Exception {
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
}
@@ -293,11 +295,11 @@
public void testImportance_locked_preUpgrade() throws Exception {
defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
}
@@ -305,39 +307,39 @@
public void testImportance_locked_unspecified_preUpgrade() throws Exception {
defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
}
@Test
public void testImportance_upgrade() throws Exception {
- StatusBarNotification sbn = getNotification(O, true /* noisy */,
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
}
@Test
public void testLights_preUpgrade_noLight() throws Exception {
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertNull(record.getLight());
}
@Test
public void testLights_preUpgrade() throws Exception {
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_LIGHT, record.getLight());
}
@@ -345,11 +347,11 @@
public void testLights_locked_preUpgrade() throws Exception {
defaultChannel.enableLights(true);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
- StatusBarNotification sbn = getNotification(N, true /* noisy */,
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
}
@@ -364,10 +366,10 @@
NotificationRecord.Light expected = new NotificationRecord.Light(
defaultLightColor, defaultLightOn, defaultLightOff);
- StatusBarNotification sbn = getNotification(O, true /* noisy */,
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, true /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(expected, record.getLight());
}
@@ -380,19 +382,19 @@
NotificationRecord.Light expected = new NotificationRecord.Light(
Color.BLUE, defaultLightOn, defaultLightOff);
- StatusBarNotification sbn = getNotification(O, true /* noisy */,
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(expected, record.getLight());
}
@Test
public void testLights_upgrade_noLight() throws Exception {
- StatusBarNotification sbn = getNotification(O, true /* noisy */,
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, O);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertNull(record.getLight());
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 8ab6d08..7bef033 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -124,7 +124,7 @@
.build();
mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
- null, System.currentTimeMillis()), getDefaultChannel(), false);
+ null, System.currentTimeMillis()), getDefaultChannel());
mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("B")
@@ -134,7 +134,7 @@
.build();
mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
- null, System.currentTimeMillis()), getDefaultChannel(), false);
+ null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("C")
@@ -142,7 +142,7 @@
.build();
mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroup, user,
- null, System.currentTimeMillis()), getDefaultChannel(), false);
+ null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("D")
@@ -150,7 +150,7 @@
.build();
mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
- null, System.currentTimeMillis()), getDefaultChannel(), false);
+ null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("E")
@@ -159,7 +159,7 @@
.build();
mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
- null, System.currentTimeMillis()), getDefaultChannel(), false);
+ null, System.currentTimeMillis()), getDefaultChannel());
mAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -373,7 +373,7 @@
assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
- assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
+ //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
}
@@ -696,14 +696,20 @@
// Returns only non-deleted channels
List<NotificationChannel> channels =
mHelper.getNotificationChannels(PKG, UID, false).getList();
- assertEquals(1, channels.size());
- compareChannels(channel2, channels.get(0));
+ assertEquals(2, channels.size()); // Default channel + non-deleted channel
+ for (NotificationChannel nc : channels) {
+ if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+ compareChannels(channel2, nc);
+ }
+ }
// Returns deleted channels too
channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
- assertEquals(2, channels.size());
+ assertEquals(3, channels.size()); // Includes default channel
for (NotificationChannel nc : channels) {
- compareChannels(channelMap.get(nc.getId()), nc);
+ if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+ compareChannels(channelMap.get(nc.getId()), nc);
+ }
}
}
@@ -801,8 +807,8 @@
mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
- // No channels remain
- assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+ // Only default channel remains
+ assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
}
@Test
@@ -881,32 +887,13 @@
mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
- // since this is a pre upgrade app, clearing data should restore the default channel
- assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
- assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID,
- mHelper.getNotificationChannels(PKG, UID, true).getList().get(0).getId());
+ assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
// Not deleted
mHelper.createNotificationChannel(PKG, UID, channel1, true);
+
mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
- assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
- }
-
- @Test
- public void testOnPackageChanged_packageRemoval_updatedPackage() throws Exception {
- // Deleted
- NotificationChannel channel1 =
- new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
- mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
- mHelper.onPackagesChanged(
- true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
- assertEquals(0, mHelper.getNotificationChannels(UPDATED_PKG, UID2, true).getList().size());
-
- // Not deleted
- mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
- mHelper.onPackagesChanged(
- false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
- assertEquals(1, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
+ assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
}
@Test
@@ -927,23 +914,7 @@
mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
- // default channel restored
- assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
- assertNull(mHelper.getNotificationChannelGroups(PKG, UID, true).getList().get(0).getId());
- }
-
- @Test
- public void testOnPackageChanged_packageRemoval_groups_upgraded() throws Exception {
- NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
- mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg, true);
- NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
- mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg2, true);
-
- mHelper.onPackagesChanged(
- true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-
- assertEquals(0,
- mHelper.getNotificationChannelGroups(UPDATED_PKG, UID2, true).getList().size());
+ assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
}
@Test
@@ -1017,8 +988,9 @@
assertEquals(3, actual.size());
for (NotificationChannelGroup group : actual) {
if (group.getId() == null) {
- assertEquals(1, group.getChannels().size());
- assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()));
+ assertEquals(2, group.getChannels().size()); // misc channel too
+ assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
+ || channel3.getId().equals(group.getChannels().get(1).getId()));
} else if (group.getId().equals(ncg.getId())) {
assertEquals(2, group.getChannels().size());
if (group.getChannels().get(0).getId().equals(channel1.getId())) {
@@ -1052,8 +1024,12 @@
List<NotificationChannelGroup> actual =
mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
- assertEquals(1, actual.size());
- assertEquals(1, actual.get(0).getChannels().size());
+ assertEquals(2, actual.size());
+ for (NotificationChannelGroup group : actual) {
+ if (Objects.equals(group.getId(), ncg.getId())) {
+ assertEquals(1, group.getChannels().size());
+ }
+ }
}
@Test
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index b1cb4d7..bc25860 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -312,7 +312,7 @@
TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
return new NotificationRecord(getContext(), new StatusBarNotification(
pkg, pkg, id, tag, 0, 0, n, user, null,
- System.currentTimeMillis()), notificationChannel, true);
+ System.currentTimeMillis()), notificationChannel);
}
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index c87eaed..711c36b8 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.platform.test.annotations.Presubmit;
@@ -97,4 +98,25 @@
testStack.stopActivityLocked(activityRecord);
}
+
+ /**
+ * This test verifies that {@link ActivityStack#STACK_VISIBLE_ACTIVITY_BEHIND} is returned from
+ * {@link ActivityStack#shouldBeVisible(ActivityRecord)} from a fullscreen workspace stack with
+ * a visible behind activity when top focused stack is the home stack.
+ */
+ @Test
+ public void testShouldBeVisibleWithVisibleBehindActivity() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TaskRecord task = createTask(service, testActivityComponent,
+ ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ final ActivityStack fullscreenWorkspaceStackId = task.getStack();
+ final ActivityStack homeStack = service.mStackSupervisor.getStack(
+ ActivityManager.StackId.HOME_STACK_ID, true /*createStaticStackIfNeeded*/,
+ true /*onTop*/);
+ final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
+ service.mStackSupervisor.setFocusStackUnchecked("testEmptyStackShouldBeVisible", homeStack);
+ service.mStackSupervisor.requestVisibleBehindLocked(activityRecord, true);
+ assertEquals(ActivityStack.STACK_VISIBLE_ACTIVITY_BEHIND,
+ fullscreenWorkspaceStackId.shouldBeVisible(null /*starting*/));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 28051f9..9cfa542 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -151,9 +151,12 @@
* setup not available in the test environment. Also specifies an injector for
*/
protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
+ private final ActivityDisplay mDisplay;
+
public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
super(service, looper);
mWindowManager = prepareMockWindowManager();
+ mDisplay = new ActivityDisplay();
}
// No home stack is set.
@@ -185,9 +188,8 @@
public <T extends ActivityStack> T createTestStack(ActivityManagerService service,
int stackId, boolean onTop) {
- final ActivityDisplay display = new ActivityDisplay();
final TestActivityContainer container =
- new TestActivityContainer(service, stackId, display, onTop);
+ new TestActivityContainer(service, stackId, mDisplay, onTop);
mActivityContainers.put(stackId, container);
return (T) container.getStack();
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 4c7bf4d..f4944f9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -7399,4 +7399,50 @@
"s21", "s22");
});
}
+
+ public void testReturnedByServer() {
+ // Package 1 updated, with manifest shortcuts.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_1);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(mManager.getManifestShortcuts())
+ .haveIds("ms1")
+ .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+
+ assertWith(mManager.getDynamicShortcuts())
+ .haveIds("s1")
+ .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+ });
+
+ // Pin them.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("ms1", "s1"), getCallingUser());
+ assertWith(getShortcutAsLauncher(USER_0))
+ .haveIds("ms1", "s1")
+ .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(mManager.getPinnedShortcuts())
+ .haveIds("ms1", "s1")
+ .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ // This shows a warning log, but should still work.
+ assertTrue(mManager.setDynamicShortcuts(mManager.getDynamicShortcuts()));
+
+ assertWith(mManager.getDynamicShortcuts())
+ .haveIds("s1")
+ .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+ });
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
index 3789086..375edf3 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
@@ -20,16 +20,31 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.job.JobService;
-import android.app.job.JobParameters;
+import android.app.job.JobServiceEngine;
+import android.app.usage.ExternalStorageStats;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.provider.Settings;
import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.storage.DiskStatsLoggingService.LogRunnable;
import libcore.io.IoUtils;
@@ -46,14 +61,17 @@
import java.io.File;
import java.io.PrintStream;
+import java.lang.reflect.Field;
import java.util.ArrayList;
@RunWith(JUnit4.class)
public class DiskStatsLoggingServiceTest extends AndroidTestCase {
@Rule public TemporaryFolder mTemporaryFolder;
@Rule public TemporaryFolder mDownloads;
- @Rule public TemporaryFolder mRootDirectory;
@Mock private AppCollector mCollector;
+ @Mock private JobService mJobService;
+ @Mock private StorageStatsManager mSsm;
+ private ExternalStorageStats mStorageStats;
private File mInputFile;
@@ -66,8 +84,10 @@
mInputFile = mTemporaryFolder.newFile();
mDownloads = new TemporaryFolder();
mDownloads.create();
- mRootDirectory = new TemporaryFolder();
- mRootDirectory.create();
+ mStorageStats = new ExternalStorageStats();
+ when(mSsm.queryExternalStatsForUser(isNull(String.class), any(UserHandle.class)))
+ .thenReturn(mStorageStats);
+ when(mJobService.getSystemService(anyString())).thenReturn(mSsm);
}
@Test
@@ -75,9 +95,9 @@
LogRunnable task = new LogRunnable();
task.setAppCollector(mCollector);
task.setDownloadsDirectory(mDownloads.getRoot());
- task.setRootDirectory(mRootDirectory.getRoot());
task.setLogOutputFile(mInputFile);
task.setSystemSize(0L);
+ task.setContext(mJobService);
task.run();
JSONObject json = getJsonOutput();
@@ -99,10 +119,10 @@
public void testPopulatedLogTask() throws Exception {
// Write data to directories.
writeDataToFile(mDownloads.newFile(), "lol");
- writeDataToFile(mRootDirectory.newFile("test.jpg"), "1234");
- writeDataToFile(mRootDirectory.newFile("test.mp4"), "12345");
- writeDataToFile(mRootDirectory.newFile("test.mp3"), "123456");
- writeDataToFile(mRootDirectory.newFile("test.whatever"), "1234567");
+ mStorageStats.audioBytes = 6L;
+ mStorageStats.imageBytes = 4L;
+ mStorageStats.videoBytes = 5L;
+ mStorageStats.totalBytes = 22L;
// Write apps.
ArrayList<PackageStats> apps = new ArrayList<>();
@@ -110,15 +130,16 @@
testApp.dataSize = 5L;
testApp.cacheSize = 55L;
testApp.codeSize = 10L;
+ testApp.userHandle = UserHandle.USER_SYSTEM;
apps.add(testApp);
- when(mCollector.getPackageStats(anyInt())).thenReturn(apps);
+ when(mCollector.getPackageStats(anyLong())).thenReturn(apps);
LogRunnable task = new LogRunnable();
task.setAppCollector(mCollector);
task.setDownloadsDirectory(mDownloads.getRoot());
- task.setRootDirectory(mRootDirectory.getRoot());
task.setLogOutputFile(mInputFile);
task.setSystemSize(10L);
+ task.setContext(mJobService);
task.run();
JSONObject json = getJsonOutput();
@@ -143,14 +164,57 @@
LogRunnable task = new LogRunnable();
task.setAppCollector(mCollector);
task.setDownloadsDirectory(mDownloads.getRoot());
- task.setRootDirectory(mRootDirectory.getRoot());
task.setLogOutputFile(mInputFile);
task.setSystemSize(10L);
+ task.setContext(mJobService);
task.run();
// No exception should be thrown.
}
+ @Test
+ public void testDontCrashOnRun() throws Exception {
+ DiskStatsLoggingService service = spy(new DiskStatsLoggingService());
+ BatteryManager batteryManager = mock(BatteryManager.class);
+ when(batteryManager.isCharging()).thenReturn(true);
+ doReturn(batteryManager).when(service).getSystemService(Context.BATTERY_SERVICE);
+ UserManager userManager = mock(UserManager.class);
+ when(userManager.getUsers()).thenReturn(new ArrayList<>());
+ doReturn(userManager).when(service).getSystemService(Context.USER_SERVICE);
+ doReturn(mSsm).when(service).getSystemService(Context.STORAGE_STATS_SERVICE);
+ doReturn(mock(StorageManager.class))
+ .when(service)
+ .getSystemService(Context.STORAGE_SERVICE);
+
+ MockContentResolver cr = new MockContentResolver();
+ cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ doReturn(cr).when(service).getContentResolver();
+
+ PackageManager pm = mock(PackageManager.class);
+ VolumeInfo volumeInfo =
+ new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, VolumeInfo.TYPE_PRIVATE, null, null);
+ when(pm.getPrimaryStorageCurrentVolume()).thenReturn(volumeInfo);
+ doReturn(pm).when(service).getPackageManager();
+
+ doReturn(0).when(service).getUserId();
+
+ // UGGGGGHHHHHHH! jobFinished is a final method on JobService which crashes when called if
+ // the JobService isn't initialized for real. ServiceTestCase doesn't let us initialize a
+ // service which is built into the framework without crashing, though, so we can't make a
+ // real initialized service.
+ //
+ // And so, we use reflection to set the JobServiceEngine, which is used by the final method,
+ // to be something which won't crash when called.
+ final Field field = JobService.class.getDeclaredField("mEngine");
+ field.setAccessible(true);
+ field.set(service, mock(JobServiceEngine.class));
+
+ // Note: This won't clobber your on-device cache file because, technically,
+ // FrameworkServicesTests don't have write permission to actually overwrite the cache file.
+ // We log and fail on the write silently in this case.
+ service.onStartJob(null);
+ }
+
private void writeDataToFile(File f, String data) throws Exception{
PrintStream out = new PrintStream(f);
out.print(data);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index e13665b..dae74db 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -16,6 +16,8 @@
package com.android.server.usage;
+import static com.android.internal.util.ArrayUtils.defeatNullable;
+
import android.app.AppOpsManager;
import android.app.usage.ExternalStorageStats;
import android.app.usage.IStorageStatsManager;
@@ -112,9 +114,12 @@
mStorage.registerListener(new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
- if ((vol.type == VolumeInfo.TYPE_PRIVATE)
- && (newState == VolumeInfo.STATE_MOUNTED)) {
- invalidateMounts();
+ switch (vol.type) {
+ case VolumeInfo.TYPE_PRIVATE:
+ case VolumeInfo.TYPE_EMULATED:
+ if (newState == VolumeInfo.STATE_MOUNTED) {
+ invalidateMounts();
+ }
}
}
});
@@ -178,9 +183,11 @@
long cacheBytes = 0;
final long token = Binder.clearCallingIdentity();
try {
- for (UserInfo user : mUser.getUsers()) {
- final StorageStats stats = queryStatsForUser(volumeUuid, user.id, null);
- cacheBytes += stats.cacheBytes;
+ if (isQuotaSupported(volumeUuid, callingPackage)) {
+ for (UserInfo user : mUser.getUsers()) {
+ final StorageStats stats = queryStatsForUser(volumeUuid, user.id, null);
+ cacheBytes += stats.cacheBytes;
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -232,7 +239,7 @@
enforcePermission(Binder.getCallingUid(), callingPackage);
}
- if (mPackage.getPackagesForUid(appInfo.uid).length == 1) {
+ if (defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1) {
// Only one package inside UID means we can fast-path
return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
} else {
@@ -276,7 +283,7 @@
enforcePermission(Binder.getCallingUid(), callingPackage);
}
- final String[] packageNames = mPackage.getPackagesForUid(uid);
+ final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
final long[] ceDataInodes = new long[packageNames.length];
String[] codePaths = new String[0];
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 03ef319..adf897d 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -22,6 +22,7 @@
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.REQUEST_REGISTERED;
import static org.junit.Assert.assertEquals;
@@ -335,14 +336,13 @@
*/
@Test
public void testCorrectLooperIsUsedForHandler() throws Exception {
- // record thread from looper.getThread and check ids.
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
.thenReturn(ERROR_INCOMPATIBLE_MODE);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mLooper.dispatchAll();
assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
- assertEquals(mLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
+ verify(mContext, never()).getMainLooper();
}
/**
@@ -361,6 +361,7 @@
altLooper.dispatchAll();
assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
+ verify(mContext).getMainLooper();
}
/**
@@ -464,11 +465,10 @@
}
/**
- * Verify the handler passed in to startLocalOnlyHotspot is correctly used for callbacks when a
- * null WifiConfig is returned.
+ * Verify callback triggered from startLocalOnlyHotspot with an incompatible mode failure.
*/
@Test
- public void testLocalOnlyHotspotCallbackFullOnNullConfig() throws Exception {
+ public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
.thenReturn(ERROR_INCOMPATIBLE_MODE);
@@ -481,6 +481,22 @@
}
/**
+ * Verify callback triggered from startLocalOnlyHotspot with a tethering disallowed failure.
+ */
+ @Test
+ public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
+ TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
+ when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
+ .thenReturn(ERROR_TETHERING_DISALLOWED);
+ mWifiManager.startLocalOnlyHotspot(callback, mHandler);
+ mLooper.dispatchAll();
+ assertEquals(ERROR_TETHERING_DISALLOWED, callback.mFailureReason);
+ assertFalse(callback.mOnStartedCalled);
+ assertFalse(callback.mOnStoppedCalled);
+ assertEquals(null, callback.mRes);
+ }
+
+ /**
* Verify a SecurityException resulting from an application without necessary permissions will
* bubble up through the call to start LocalOnlyHotspot and will not trigger other callbacks.
*/
@@ -616,12 +632,11 @@
*/
@Test
public void testCorrectLooperIsUsedForObserverHandler() throws Exception {
- // record thread from looper.getThread and check ids.
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
mLooper.dispatchAll();
assertTrue(observer.mOnRegistered);
- assertEquals(mLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
+ verify(mContext, never()).getMainLooper();
}
/**
@@ -638,6 +653,7 @@
altLooper.dispatchAll();
assertTrue(observer.mOnRegistered);
assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
+ verify(mContext).getMainLooper();
}
/**