Merge "remove unneeded RecordedOps"
diff --git a/api/system-current.txt b/api/system-current.txt
index d62c43e..ea1f1a1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1062,7 +1062,11 @@
}
public class PackageItemInfo {
- method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
+ method public deprecated java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
+ method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager, float, int);
+ field public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
+ field public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
+ field public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
}
public abstract class PackageManager {
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 3a28bdf..41a39fd 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -922,6 +922,7 @@
Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageUserState;-><init>()V
Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
+Landroid/content/pm/ShortcutInfo;->getIcon()Landroid/graphics/drawable/Icon;
Landroid/content/pm/ShortcutManager;->mService:Landroid/content/pm/IShortcutService;
Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
Landroid/content/pm/UserInfo;-><init>(ILjava/lang/String;I)V
@@ -2500,6 +2501,7 @@
Landroid/service/voice/VoiceInteractionService;->isKeyphraseAndLocaleSupportedForHotword(Ljava/lang/String;Ljava/util/Locale;)Z
Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
+Landroid/speech/tts/TtsEngines;-><init>(Landroid/content/Context;)V
Landroid/system/Int32Ref;->value:I
Landroid/system/OsConstants;-><init>()V
Landroid/system/OsConstants;->AF_NETLINK:I
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 8c0cd23..4b84ed4 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -64,6 +64,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -668,7 +669,17 @@
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
String libraryPermittedPath = mDataDir;
+
if (isBundledApp) {
+ // For bundled apps, add the base directory of the app (e.g.,
+ // /system/app/Foo/) to the permitted paths so that it can load libraries
+ // embedded in module apks under the directory. For now, GmsCore is relying
+ // on this, but this isn't specific to the app. Also note that, we don't
+ // need to do this for unbundled apps as entire /data is already set to
+ // the permitted paths for them.
+ libraryPermittedPath += File.pathSeparator
+ + Paths.get(getAppDir()).getParent().toString();
+
// This is necessary to grant bundled apps access to
// libraries located in subdirectories of /system/lib
libraryPermittedPath += File.pathSeparator + defaultSearchPaths;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 08e2c91..22367b2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3725,7 +3725,7 @@
*/
public static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
- | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+ | DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS;
/**
* Called by an application that is administering the device to request that the storage system
@@ -4738,12 +4738,14 @@
* <ul>
* <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which affects the parent user, but only if there
* is no separate challenge set on the managed profile.
- * <li>{@link #KEYGUARD_DISABLE_FINGERPRINT} which affects the managed profile challenge if
+ * <li>{@link #KEYGUARD_DISABLE_FINGERPRINT}, {@link #KEYGUARD_DISABLE_FACE} or
+ * {@link #KEYGUARD_DISABLE_IRIS} which affects the managed profile challenge if
* there is one, or the parent user otherwise.
* <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} which affects notifications generated
* by applications in the managed profile.
* </ul>
- * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} and {@link #KEYGUARD_DISABLE_FINGERPRINT} can also be
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT},
+ * {@link #KEYGUARD_DISABLE_FACE} and {@link #KEYGUARD_DISABLE_IRIS} can also be
* set on the {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
@@ -4754,12 +4756,16 @@
* {@link #getKeyguardDisabledFeatures(ComponentName)}
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param which {@link #KEYGUARD_DISABLE_FEATURES_NONE} (default),
+ * @param which The disabled features flag which can be either
+ * {@link #KEYGUARD_DISABLE_FEATURES_NONE} (default),
+ * {@link #KEYGUARD_DISABLE_FEATURES_ALL}, or a combination of
* {@link #KEYGUARD_DISABLE_WIDGETS_ALL}, {@link #KEYGUARD_DISABLE_SECURE_CAMERA},
* {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS},
* {@link #KEYGUARD_DISABLE_TRUST_AGENTS},
* {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS},
- * {@link #KEYGUARD_DISABLE_FINGERPRINT}, {@link #KEYGUARD_DISABLE_FEATURES_ALL}
+ * {@link #KEYGUARD_DISABLE_FINGERPRINT},
+ * {@link #KEYGUARD_DISABLE_FACE},
+ * {@link #KEYGUARD_DISABLE_IRIS}.
* @throws SecurityException if {@code admin} is not an active administrator or does not user
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
*/
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 6e633426..a10cc12 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -261,6 +261,7 @@
result = prime * result + state;
result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode());
+ result = prime * result + ((category == null) ? 0 : category.hashCode());
result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode());
return result;
}
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 07fbfb5..14d3f91 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -16,6 +16,10 @@
package android.content.pm;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.res.XmlResourceParser;
@@ -29,7 +33,11 @@
import android.util.Printer;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
import java.text.Collator;
+import java.util.BitSet;
import java.util.Comparator;
/**
@@ -42,10 +50,56 @@
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
- private static final float MAX_LABEL_SIZE_PX = 500f;
+ private static final int LINE_FEED_CODE_POINT = 10;
+ private static final int NBSP_CODE_POINT = 160;
+
/** The maximum length of a safe label, in characters */
private static final int MAX_SAFE_LABEL_LENGTH = 50000;
+ /** @hide */
+ public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
+
+ /**
+ * Flags for {@link #loadSafeLabel(PackageManager, float, int)}
+ *
+ * @hide
+ */
+ @Retention(SOURCE)
+ @IntDef(flag = true, prefix = "SAFE_LABEL_FLAG_",
+ value = {SAFE_LABEL_FLAG_TRIM, SAFE_LABEL_FLAG_SINGLE_LINE,
+ SAFE_LABEL_FLAG_FIRST_LINE})
+ public @interface SafeLabelFlags {}
+
+ /**
+ * Remove {@link Character#isWhitespace(int) whitespace} and non-breaking spaces from the edges
+ * of the label.
+ *
+ * @see #loadSafeLabel(PackageManager, float, int)
+ * @hide
+ */
+ @SystemApi
+ public static final int SAFE_LABEL_FLAG_TRIM = 0x1;
+
+ /**
+ * Force entire string into single line of text (no newlines). Cannot be set at the same time as
+ * {@link #SAFE_LABEL_FLAG_FIRST_LINE}.
+ *
+ * @see #loadSafeLabel(PackageManager, float, int)
+ * @hide
+ */
+ @SystemApi
+ public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 0x2;
+
+ /**
+ * Return only first line of text (truncate at first newline). Cannot be set at the same time as
+ * {@link #SAFE_LABEL_FLAG_SINGLE_LINE}.
+ *
+ * @see #loadSafeLabel(PackageManager, float, int)
+ * @hide
+ */
+ @SystemApi
+ public static final int SAFE_LABEL_FLAG_FIRST_LINE = 0x4;
+
private static volatile boolean sForceSafeLabels = false;
/** {@hide} */
@@ -140,7 +194,8 @@
*/
public @NonNull CharSequence loadLabel(@NonNull PackageManager pm) {
if (sForceSafeLabels) {
- return loadSafeLabel(pm);
+ return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_LABEL_FLAG_TRIM
+ | SAFE_LABEL_FLAG_FIRST_LINE);
} else {
return loadUnsafeLabel(pm);
}
@@ -163,66 +218,226 @@
return packageName;
}
+ private static boolean isNewline(int codePoint) {
+ int type = Character.getType(codePoint);
+ return type == Character.PARAGRAPH_SEPARATOR || type == Character.LINE_SEPARATOR
+ || codePoint == LINE_FEED_CODE_POINT;
+ }
+
+ private static boolean isWhiteSpace(int codePoint) {
+ return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT;
+ }
+
/**
- * Same as {@link #loadLabel(PackageManager)} with the addition that
- * the returned label is safe for being presented in the UI since it
- * will not contain new lines and the length will be limited to a
- * reasonable amount. This prevents a malicious party to influence UI
- * layout via the app label misleading the user into performing a
- * detrimental for them action. If the label is too long it will be
- * truncated and ellipsized at the end.
+ * @hide
+ * @deprecated use loadSafeLabel(PackageManager, float, int) instead
+ */
+ @SystemApi
+ @Deprecated
+ public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
+ return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_LABEL_FLAG_TRIM
+ | SAFE_LABEL_FLAG_FIRST_LINE);
+ }
+
+ /**
+ * A special string manipulation class. Just records removals and executes the when onString()
+ * is called.
+ */
+ private static class StringWithRemovedChars {
+ /** The original string */
+ private final String mOriginal;
+
+ /**
+ * One bit per char in string. If bit is set, character needs to be removed. If whole
+ * bit field is not initialized nothing needs to be removed.
+ */
+ private BitSet mRemovedChars;
+
+ StringWithRemovedChars(@NonNull String original) {
+ mOriginal = original;
+ }
+
+ /**
+ * Mark all chars in a range {@code [firstRemoved - firstNonRemoved[} (not including
+ * firstNonRemoved) as removed.
+ */
+ void removeRange(int firstRemoved, int firstNonRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(firstRemoved, firstNonRemoved);
+ }
+
+ /**
+ * Remove all characters before {@code firstNonRemoved}.
+ */
+ void removeAllCharBefore(int firstNonRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(0, firstNonRemoved);
+ }
+
+ /**
+ * Remove all characters after and including {@code firstRemoved}.
+ */
+ void removeAllCharAfter(int firstRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(firstRemoved, mOriginal.length());
+ }
+
+ @Override
+ public String toString() {
+ // Common case, no chars removed
+ if (mRemovedChars == null) {
+ return mOriginal;
+ }
+
+ StringBuilder sb = new StringBuilder(mOriginal.length());
+ for (int i = 0; i < mOriginal.length(); i++) {
+ if (!mRemovedChars.get(i)) {
+ sb.append(mOriginal.charAt(i));
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return length or the original string
+ */
+ int length() {
+ return mOriginal.length();
+ }
+
+ /**
+ * Return if a certain {@code offset} of the original string is removed
+ */
+ boolean isRemoved(int offset) {
+ return mRemovedChars != null && mRemovedChars.get(offset);
+ }
+
+ /**
+ * Return codePoint of original string at a certain {@code offset}
+ */
+ int codePointAt(int offset) {
+ return mOriginal.codePointAt(offset);
+ }
+ }
+
+ /**
+ * Load, clean up and truncate label before use.
*
- * @param pm A PackageManager from which the label can be loaded; usually
- * the PackageManager from which you originally retrieved this item
- * @return Returns a CharSequence containing the item's label. If the
- * item does not have a label, its name is returned.
+ * <p>This method is meant to remove common mistakes and nefarious formatting from strings that
+ * are used in sensitive parts of the UI.
*
+ * <p>This method first treats the string like HTML and then ...
+ * <ul>
+ * <li>Removes new lines or truncates at first new line
+ * <li>Trims the white-space off the end
+ * <li>Truncates the string to a given length
+ * </ul>
+ * ... if specified.
+ *
+ * @param ellipsizeDip Assuming maximum length of the string (in dip), assuming font size 42.
+ * This is roughly 50 characters for {@code ellipsizeDip == 1000}.<br />
+ * Usually ellipsizing should be left to the view showing the string. If a
+ * string is used as an input to another string, it might be useful to
+ * control the length of the input string though. {@code 0} disables this
+ * feature.
+ * @return The safe label
* @hide
*/
@SystemApi
- public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
+ public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm,
+ @FloatRange(from = 0) float ellipsizeDip, @SafeLabelFlags int flags) {
+ boolean onlyKeepFirstLine = ((flags & SAFE_LABEL_FLAG_FIRST_LINE) != 0);
+ boolean forceSingleLine = ((flags & SAFE_LABEL_FLAG_SINGLE_LINE) != 0);
+ boolean trim = ((flags & SAFE_LABEL_FLAG_TRIM) != 0);
+
+ Preconditions.checkNotNull(pm);
+ Preconditions.checkArgument(ellipsizeDip >= 0);
+ Preconditions.checkFlagsArgument(flags, SAFE_LABEL_FLAG_TRIM | SAFE_LABEL_FLAG_SINGLE_LINE
+ | SAFE_LABEL_FLAG_FIRST_LINE);
+ Preconditions.checkArgument(!(onlyKeepFirstLine && forceSingleLine),
+ "Cannot set SAFE_LABEL_FLAG_SINGLE_LINE and SAFE_LABEL_FLAG_FIRST_LINE at the same "
+ + "time");
+
// loadLabel() always returns non-null
String label = loadUnsafeLabel(pm).toString();
- // strip HTML tags to avoid <br> and other tags overwriting original message
- String labelStr = Html.fromHtml(label).toString();
- // If the label contains new line characters it may push the UI
- // down to hide a part of it. Labels shouldn't have new line
- // characters, so just truncate at the first time one is seen.
- final int labelLength = Math.min(labelStr.length(), MAX_SAFE_LABEL_LENGTH);
- final StringBuffer sb = new StringBuffer(labelLength);
- int offset = 0;
- while (offset < labelLength) {
- final int codePoint = labelStr.codePointAt(offset);
- final int type = Character.getType(codePoint);
- if (type == Character.LINE_SEPARATOR
- || type == Character.CONTROL
- || type == Character.PARAGRAPH_SEPARATOR) {
- labelStr = labelStr.substring(0, offset);
+ // Treat string as HTML. This
+ // - converts HTML symbols: e.g. ß -> ß
+ // - applies some HTML tags: e.g. <br> -> \n
+ // - removes invalid characters such as \b
+ // - removes html styling, such as <b>
+ // - applies html formatting: e.g. a<p>b</p>c -> a\n\nb\n\nc
+ // - replaces some html tags by "object replacement" markers: <img> -> \ufffc
+ // - Removes leading white space
+ // - Removes all trailing white space beside a single space
+ // - Collapses double white space
+ StringWithRemovedChars labelStr = new StringWithRemovedChars(
+ Html.fromHtml(label).toString());
+
+ int firstNonWhiteSpace = -1;
+ int firstTrailingWhiteSpace = -1;
+
+ // Remove new lines (if requested) and control characters.
+ int labelLength = labelStr.length();
+ for (int offset = 0; offset < labelLength; ) {
+ int codePoint = labelStr.codePointAt(offset);
+ int type = Character.getType(codePoint);
+ int codePointLen = Character.charCount(codePoint);
+ boolean isNewline = isNewline(codePoint);
+
+ if (offset > MAX_SAFE_LABEL_LENGTH || onlyKeepFirstLine && isNewline) {
+ labelStr.removeAllCharAfter(offset);
break;
+ } else if (forceSingleLine && isNewline) {
+ labelStr.removeRange(offset, offset + codePointLen);
+ } else if (type == Character.CONTROL && !isNewline) {
+ labelStr.removeRange(offset, offset + codePointLen);
+ } else if (trim && !isWhiteSpace(codePoint)) {
+ // This is only executed if the code point is not removed
+ if (firstNonWhiteSpace == -1) {
+ firstNonWhiteSpace = offset;
+ }
+ firstTrailingWhiteSpace = offset + codePointLen;
}
- // replace all non-break space to " " in order to be trimmed
- final int charCount = Character.charCount(codePoint);
- if (type == Character.SPACE_SEPARATOR) {
- sb.append(' ');
+
+ offset += codePointLen;
+ }
+
+ if (trim) {
+ // Remove leading and trailing white space
+ if (firstNonWhiteSpace == -1) {
+ // No non whitespace found, remove all
+ labelStr.removeAllCharAfter(0);
} else {
- sb.append(labelStr.charAt(offset));
- if (charCount == 2) {
- sb.append(labelStr.charAt(offset + 1));
+ if (firstNonWhiteSpace > 0) {
+ labelStr.removeAllCharBefore(firstNonWhiteSpace);
+ }
+ if (firstTrailingWhiteSpace < labelLength) {
+ labelStr.removeAllCharAfter(firstTrailingWhiteSpace);
}
}
- offset += charCount;
}
- labelStr = sb.toString().trim();
- if (labelStr.isEmpty()) {
- return packageName;
- }
- TextPaint paint = new TextPaint();
- paint.setTextSize(42);
+ if (ellipsizeDip == 0) {
+ return labelStr.toString();
+ } else {
+ // Truncate
+ final TextPaint paint = new TextPaint();
+ paint.setTextSize(42);
- return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX,
- TextUtils.TruncateAt.END);
+ return TextUtils.ellipsize(labelStr.toString(), paint, ellipsizeDip,
+ TextUtils.TruncateAt.END);
+ }
}
/**
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 1f2b90a..3820798 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -282,7 +282,12 @@
@Nullable SelectionResult result) {
final Layout layout = mTextView.getLayout();
- final Runnable onAnimationEndCallback = () -> startSelectionActionMode(result);
+ final String originalText = getText(mTextView).toString();
+ final Runnable onAnimationEndCallback = () -> {
+ if (TextUtils.equals(getText(mTextView), originalText)) {
+ startSelectionActionMode(result);
+ }
+ };
// TODO do not trigger the animation if the change included only non-printable characters
final boolean didSelectionChange =
result != null && (mTextView.getSelectionStart() != result.mStart
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5380cd8..4a2c2c5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2284,7 +2284,7 @@
* Sets the key listener to be used with this TextView. This can be null
* to disallow user input. Note that this method has significant and
* subtle interactions with soft keyboards and other input method:
- * see {@link KeyListener#getInputType() KeyListener.getContentType()}
+ * see {@link KeyListener#getInputType() KeyListener.getInputType()}
* for important details. Calling this method will replace the current
* content type of the text view with the content type returned by the
* key listener.
diff --git a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
index 9966626..ce2d229 100644
--- a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
+++ b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
@@ -82,7 +83,10 @@
final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
null /*root*/);
((TextView) view.findViewById(R.id.app_name_text))
- .setText(applicationInfo.loadSafeLabel(getPackageManager()));
+ .setText(applicationInfo.loadSafeLabel(getPackageManager(),
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
+ | PackageItemInfo.SAFE_LABEL_FLAG_TRIM));
((TextView) view.findViewById(R.id.message))
.setText(mHarmfulAppWarning);
return view;
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index dd9bafe..462d052 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -49,6 +49,38 @@
return NULL;
}
+bool AssetStreamAdaptor::hasPosition() const {
+ return fAsset->seek(0, SEEK_CUR) != -1;
+}
+
+size_t AssetStreamAdaptor::getPosition() const {
+ const off64_t offset = fAsset->seek(0, SEEK_CUR);
+ if (offset == -1) {
+ SkDebugf("---- fAsset->seek(0, SEEK_CUR) failed\n");
+ return 0;
+ }
+
+ return offset;
+}
+
+bool AssetStreamAdaptor::seek(size_t position) {
+ if (fAsset->seek(position, SEEK_SET) == -1) {
+ SkDebugf("---- fAsset->seek(0, SEEK_SET) failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool AssetStreamAdaptor::move(long offset) {
+ if (fAsset->seek(offset, SEEK_CUR) == -1) {
+ SkDebugf("---- fAsset->seek(%i, SEEK_CUR) failed\n", offset);
+ return false;
+ }
+
+ return true;
+}
+
size_t AssetStreamAdaptor::read(void* buffer, size_t size) {
ssize_t amount;
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index 2f2ee96..ac291ea 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -34,6 +34,10 @@
virtual size_t read(void* buffer, size_t size);
virtual bool hasLength() const { return true; }
virtual size_t getLength() const;
+ virtual bool hasPosition() const;
+ virtual size_t getPosition() const;
+ virtual bool seek(size_t position);
+ virtual bool move(long offset);
virtual bool isAtEnd() const;
protected:
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 62d78e7..f0da660 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -219,8 +219,20 @@
SkPaint tmpPaint;
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
- mRecorder.drawImageLattice(image.get(), lattice, dst,
- bitmapPaint(paint, &tmpPaint, colorFilter));
+ const SkPaint* filteredPaint = bitmapPaint(paint, &tmpPaint, colorFilter);
+ // Besides kNone, the other three SkFilterQualities are treated the same. And Android's
+ // Java API only supports kLow and kNone anyway.
+ if (!filteredPaint || filteredPaint->getFilterQuality() == kNone_SkFilterQuality) {
+ if (filteredPaint != &tmpPaint) {
+ if (paint) {
+ tmpPaint = *paint;
+ }
+ filteredPaint = &tmpPaint;
+ }
+ tmpPaint.setFilterQuality(kLow_SkFilterQuality);
+ }
+
+ mRecorder.drawImageLattice(image.get(), lattice, dst, filteredPaint);
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index a2d2ddf..f878822 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -265,7 +265,7 @@
mFile = new AtomicFile(new File(new File(
Environment.getDataUserCePackageDirectory(
StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
- "assistant"), "block_stats.xml"));
+ "assistant"), "blocking_helper_stats.xml"));
loadFile();
for (StatusBarNotification sbn : getActiveNotifications()) {
onNotificationPosted(sbn);
diff --git a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
index 8908ebd..29ee920 100644
--- a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
+++ b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
@@ -32,7 +32,7 @@
private static final String TAG = "ExtAssistant.CI";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- static final float DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT = .4f;
+ static final float DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT = .8f;
static final int DEFAULT_STREAK_LIMIT = 2;
static final String ATT_DISMISSALS = "dismisses";
static final String ATT_VIEWS = "views";
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index 56cb888..e6ea2d8 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -21,6 +21,7 @@
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
@@ -51,10 +52,14 @@
try {
PackageManager pm = getPackageManager();
- CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(
- pm.getApplicationInfo(mCallingPkg, 0).loadSafeLabel(pm).toString());
- CharSequence app2 = BidiFormatter.getInstance().unicodeWrap(
- pm.getApplicationInfo(mProviderPkg, 0).loadSafeLabel(pm).toString());
+ CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo(
+ mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+ | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE).toString());
+ CharSequence app2 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo(
+ mProviderPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+ | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE).toString());
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(getString(R.string.slice_permission_title, app1, app2))
.setView(R.layout.slice_permission_request)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8adf4bc..3454fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -469,6 +469,7 @@
updateNotificationColor();
if (mMenuRow != null) {
mMenuRow.onNotificationUpdated(mStatusBarNotification);
+ mMenuRow.setAppName(mAppName);
}
if (mIsSummaryWithChildren) {
mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index d44fe4d..3865b27 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -23,7 +23,6 @@
import static com.android.internal.util.Preconditions.checkState;
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
-import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -39,6 +38,7 @@
import android.content.ServiceConnection;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.net.NetworkPolicyManager;
import android.os.Binder;
@@ -289,7 +289,10 @@
String packageTitle = BidiFormatter.getInstance().unicodeWrap(
getPackageInfo(callingPackage, userId)
.applicationInfo
- .loadSafeLabel(getContext().getPackageManager())
+ .loadSafeLabel(getContext().getPackageManager(),
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+ | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE)
.toString());
long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index a4d0dc8..74b4543 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -812,9 +812,9 @@
LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getDurationMillis(
KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
- !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
+ !COMPRESS_TIME ? 3 * 60 * 1000L : 15 * 1000L);
LIGHT_PRE_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_LIGHT_PRE_IDLE_TIMEOUT,
- !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L);
+ !COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L);
LIGHT_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_LIGHT_IDLE_TIMEOUT,
!COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
LIGHT_IDLE_FACTOR = mParser.getFloat(KEY_LIGHT_IDLE_FACTOR,
diff --git a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java b/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java
index d9878cd..e5add58 100644
--- a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java
+++ b/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java
@@ -23,13 +23,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.SystemPropertiesProto;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
-import android.widget.CheckBox;
import com.android.internal.R;
import com.android.server.utils.AppInstallerUtil;
@@ -45,7 +44,10 @@
mPackageName = appInfo.packageName;
final PackageManager pm = context.getPackageManager();
- final CharSequence label = appInfo.loadSafeLabel(pm);
+ final CharSequence label = appInfo.loadSafeLabel(pm,
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
+ | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
final CharSequence message = context.getString(R.string.deprecated_target_sdk_message);
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
diff --git a/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java b/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java
index b6f6ae6..7348a0d 100644
--- a/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java
+++ b/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.view.Window;
import android.view.WindowManager;
@@ -37,7 +38,10 @@
mPackageName = appInfo.packageName;
final PackageManager pm = context.getPackageManager();
- final CharSequence label = appInfo.loadSafeLabel(pm);
+ final CharSequence label = appInfo.loadSafeLabel(pm,
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
+ | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
final CharSequence message = context.getString(R.string.unsupported_compile_sdk_message,
label);
diff --git a/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java b/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java
index 8850663..1d6438c 100644
--- a/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java
+++ b/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java
@@ -21,6 +21,7 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.view.Window;
import android.view.WindowManager;
@@ -35,7 +36,10 @@
mPackageName = appInfo.packageName;
final PackageManager pm = context.getPackageManager();
- final CharSequence label = appInfo.loadSafeLabel(pm);
+ final CharSequence label = appInfo.loadSafeLabel(pm,
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
+ | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
final CharSequence message = context.getString(
R.string.unsupported_display_size_message, label);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5a91ea9..93ef315 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -524,16 +524,13 @@
// SCO audio state is active or starting due to a request from AudioManager API
private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
// SCO audio deactivation request waiting for headset service to connect
- private static final int SCO_STATE_DEACTIVATE_REQ = 5;
+ private static final int SCO_STATE_DEACTIVATE_REQ = 4;
// SCO audio deactivation in progress, waiting for Bluetooth audio intent
- private static final int SCO_STATE_DEACTIVATING = 6;
+ private static final int SCO_STATE_DEACTIVATING = 5;
// SCO audio state is active due to an action in BT handsfree (either voice recognition or
// in call audio)
private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
- // Deactivation request for all SCO connections (initiated by audio mode change)
- // waiting for headset service to connect
- private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
// Indicates the mode used for SCO audio connection. The mode is virtual call if the request
// originated from an app targeting an API version before JB MR2 and raw audio after that.
@@ -3593,33 +3590,19 @@
return result;
}
+ /**
+ * Disconnect all SCO connections started by {@link AudioManager} except those started by
+ * {@param exceptPid}
+ *
+ * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept
+ */
private void disconnectBluetoothSco(int exceptPid) {
synchronized(mScoClients) {
checkScoAudioState();
- if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
- mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
- if (mBluetoothHeadsetDevice != null) {
- if (mBluetoothHeadset != null) {
- boolean status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, SCO_MODE_RAW)
- || disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, SCO_MODE_VIRTUAL_CALL)
- || disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, SCO_MODE_VR);
- if (status) {
- mScoAudioState = SCO_STATE_DEACTIVATING;
- } else {
- clearAllScoClients(exceptPid, false);
- mScoAudioState = SCO_STATE_INACTIVE;
- }
- } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
- getBluetoothHeadset()) {
- mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
- }
- }
- } else {
- clearAllScoClients(exceptPid, true);
+ if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
+ return;
}
+ clearAllScoClients(exceptPid, true);
}
}
@@ -3785,8 +3768,7 @@
checkScoAudioState();
// Continue pending action if any
if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
- mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
- mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
+ mScoAudioState == SCO_STATE_DEACTIVATE_REQ) {
boolean status = false;
if (mBluetoothHeadsetDevice != null) {
switch (mScoAudioState) {
@@ -3804,17 +3786,6 @@
mScoAudioState = SCO_STATE_DEACTIVATING;
}
break;
- case SCO_STATE_DEACTIVATE_EXT_REQ:
- status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, SCO_MODE_RAW) ||
- disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, SCO_MODE_VIRTUAL_CALL) ||
- disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, SCO_MODE_VR);
- if (status) {
- mScoAudioState = SCO_STATE_DEACTIVATING;
- }
- break;
}
}
if (!status) {
@@ -6397,8 +6368,7 @@
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
- mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
- mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
+ mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
setBluetoothScoOn(true);
@@ -6422,8 +6392,7 @@
break;
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
- mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
- mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
+ mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
default:
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8562572..a6dfec7 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -680,7 +680,7 @@
* @throws SecurityException if the permission check fails
*/
private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
- getContext().enforceCallingOrSelfPermission(
+ getContext().enforceCallingPermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
}
@@ -691,8 +691,7 @@
* @throws SecurityException if the permission check fails
*/
private void enforceDumpPermission(@NonNull final String message) {
- getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
- message);
+ getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message);
}
};
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 12dfd9a..72d1ae9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8804,7 +8804,7 @@
// equal to the version on the /data partition. Throw an exception and use
// the application already installed on the /data partition.
throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
- + pkg.codePath + " ignored: updated version " + disabledPkgSetting.versionCode
+ + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
+ " better than this " + pkg.getLongVersionCode());
}
@@ -11194,8 +11194,23 @@
mSettings.getPackageLPr(pkg.packageName),
"previous package state not present");
+ // previousPkg.pkg may be null: the package will be not be scanned if the
+ // package manager knows there is a newer version on /data.
+ // TODO[b/79435695]: Find a better way to keep track of the "static"
+ // property for RROs instead of having to parse packages on /system
+ PackageParser.Package ppkg = previousPkg.pkg;
+ if (ppkg == null) {
+ try {
+ final PackageParser pp = new PackageParser();
+ ppkg = pp.parsePackage(previousPkg.codePath,
+ parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR);
+ } catch (PackageParserException e) {
+ Slog.w(TAG, "failed to parse " + previousPkg.codePath, e);
+ }
+ }
+
// Static overlays cannot be updated.
- if (previousPkg.pkg.mOverlayIsStatic) {
+ if (ppkg != null && ppkg.mOverlayIsStatic) {
throw new PackageManagerException("Overlay " + pkg.packageName +
" is static and cannot be upgraded.");
// Non-static overlays cannot be converted to static overlays.