Merge "Simply logic for connect and disconnect in HeadsetProfile" am: 7aae482135
am: 474e4f3163
Change-Id: I45ec4ad0a2128491356982898780e7046b8f5be3
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8ffe5bf..ed6c25d 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -302,6 +302,7 @@
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
+ mTargetInset = -1;
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
@@ -942,6 +943,7 @@
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
}
+ handleViewport(frameDuration);
eglSwapBuffers(mDisplay, mSurface);
@@ -966,7 +968,7 @@
usleep(part.pause * ns2us(frameDuration));
// For infinite parts, we've now played them at least once, so perhaps exit
- if(exitPending() && !part.count)
+ if(exitPending() && !part.count && mCurrentInset >= mTargetInset)
break;
}
@@ -986,6 +988,51 @@
return true;
}
+void BootAnimation::handleViewport(nsecs_t timestep) {
+ if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
+ return;
+ }
+ if (mTargetInset < 0) {
+ // Poll the amount for the top display inset. This will return -1 until persistent properties
+ // have been loaded.
+ mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top",
+ -1 /* default */, -1 /* min */, mHeight / 2 /* max */);
+ }
+ if (mTargetInset <= 0) {
+ return;
+ }
+
+ if (mCurrentInset < mTargetInset) {
+ // After the device boots, the inset will effectively be cropped away. We animate this here.
+ float fraction = static_cast<float>(mCurrentInset) / mTargetInset;
+ int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset;
+
+ SurfaceComposerClient::Transaction()
+ .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight))
+ .apply();
+ } else {
+ // At the end of the animation, we switch to the viewport that DisplayManager will apply
+ // later. This changes the coordinate system, and means we must move the surface up by
+ // the inset amount.
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+
+ Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
+ Rect displayRect(0, mTargetInset, mWidth, mHeight);
+
+ SurfaceComposerClient::Transaction t;
+ t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
+ .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
+ t.setDisplayProjection(dtoken, 0 /* orientation */, layerStackRect, displayRect);
+ t.apply();
+
+ mTargetInset = mCurrentInset = 0;
+ }
+
+ int delta = timestep * mTargetInset / ms2ns(200);
+ mCurrentInset += delta;
+}
+
void BootAnimation::releaseAnimation(Animation* animation) const
{
for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 56e131523..b4699d8 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -157,11 +157,15 @@
void checkExit();
+ void handleViewport(nsecs_t timestep);
+
sp<SurfaceComposerClient> mSession;
AssetManager mAssets;
Texture mAndroid[2];
int mWidth;
int mHeight;
+ int mCurrentInset;
+ int mTargetInset;
bool mUseNpotTextures = false;
EGLDisplay mDisplay;
EGLDisplay mContext;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index be2e2fa..f0a0e88 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -30,7 +30,6 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -190,12 +189,10 @@
* content and also the accessibility service will receive accessibility events from
* them.
* <p>
- * <strong>Note:</strong> For accessibility services targeting API version
- * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
- * set for the system to regard views that are not important for accessibility. For
- * accessibility services targeting API version lower than
- * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
- * regarded for accessibility purposes.
+ * <strong>Note:</strong> For accessibility services targeting Android 4.1 (API level 16) or
+ * higher, this flag has to be explicitly set for the system to regard views that are not
+ * important for accessibility. For accessibility services targeting Android 4.0.4 (API level
+ * 15) or lower, this flag is ignored and all views are regarded for accessibility purposes.
* </p>
* <p>
* Usually views not important for accessibility are layout managers that do not
@@ -220,19 +217,19 @@
* flag does not guarantee that the device will not be in touch exploration
* mode since there may be another enabled service that requested it.
* <p>
- * For accessibility services targeting API version higher than
- * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
- * this flag have to declare this capability in their meta-data by setting
- * the attribute {@link android.R.attr#canRequestTouchExplorationMode
- * canRequestTouchExplorationMode} to true, otherwise this flag will
+ * For accessibility services targeting Android 4.3 (API level 18) or higher
+ * that want to set this flag have to declare this capability in their
+ * meta-data by setting the attribute
+ * {@link android.R.attr#canRequestTouchExplorationMode
+ * canRequestTouchExplorationMode} to true. Otherwise, this flag will
* be ignored. For how to declare the meta-data of a service refer to
* {@value AccessibilityService#SERVICE_META_DATA}.
* </p>
* <p>
- * Services targeting API version equal to or lower than
- * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
- * the first time they are run, if this flag is specified, a dialog is
- * shown to the user to confirm enabling explore by touch.
+ * Services targeting Android 4.2.2 (API level 17) or lower will work
+ * normally. In other words, the first time they are run, if this flag is
+ * specified, a dialog is shown to the user to confirm enabling explore by
+ * touch.
* </p>
* @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
*/
@@ -388,10 +385,10 @@
public int feedbackType;
/**
- * The timeout after the most recent event of a given type before an
+ * The timeout, in milliseconds, after the most recent event of a given type before an
* {@link AccessibilityService} is notified.
* <p>
- * <strong>Can be dynamically set at runtime.</strong>.
+ * <strong>Can be dynamically set at runtime.</strong>
* </p>
* <p>
* <strong>Note:</strong> The event notification timeout is useful to avoid propagating
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7f4ea1d..cdcba9b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6377,6 +6377,10 @@
}
void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ if (args != null && args.length > 0 && args[0].equals("--autofill")) {
+ dumpAutofillManager(prefix, writer);
+ return;
+ }
writer.print(prefix); writer.print("Local Activity ");
writer.print(Integer.toHexString(System.identityHashCode(this)));
writer.println(" State:");
@@ -6404,16 +6408,20 @@
mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
+ dumpAutofillManager(prefix, writer);
+
+ ResourcesManager.getInstance().dump(prefix, writer);
+ }
+
+ void dumpAutofillManager(String prefix, PrintWriter writer) {
final AutofillManager afm = getAutofillManager();
if (afm != null) {
+ afm.dump(prefix, writer);
writer.print(prefix); writer.print("Autofill Compat Mode: ");
writer.println(isAutofillCompatibilityEnabled());
- afm.dump(prefix, writer);
} else {
writer.print(prefix); writer.println("No AutofillManager");
}
-
- ResourcesManager.getInstance().dump(prefix, writer);
}
/**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9b6764d..14cae95 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -413,4 +413,9 @@
* @return The intent used to launch the home activity.
*/
public abstract Intent getHomeIntent();
+
+ /**
+ * WindowManager notifies AM when display size of the default display changes.
+ */
+ public abstract void notifyDefaultDisplaySizeChanged();
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index b2b85d4..d526bcc 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -960,14 +960,15 @@
}
/**
- * Sets the bounds (window size) that the activity should be launched in.
+ * Sets the bounds (window size and position) that the activity should be launched in.
* Rect position should be provided in pixels and in screen coordinates.
- * Set to null explicitly for fullscreen.
+ * Set to {@code null} to explicitly launch fullscreen.
* <p>
- * <strong>NOTE:<strong/> This value is ignored on devices that don't have
+ * <strong>NOTE:</strong> This value is ignored on devices that don't have
* {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
* {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
- * @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen.
+ * @param screenSpacePixelRect launch bounds or {@code null} for fullscreen
+ * @return {@code this} {@link ActivityOptions} instance
*/
public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) {
mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9c516d2..9e06e9f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -147,6 +147,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -5244,6 +5245,16 @@
}
}
+ /**
+ * Updates the application info.
+ *
+ * This only works in the system process. Must be called on the main thread.
+ */
+ public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) {
+ Preconditions.checkState(mSystemThread, "Must only be called in the system process");
+ handleApplicationInfoChanged(ai);
+ }
+
void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
// Updates triggered by package installation go through a package update
// receiver. Here we try to capture ApplicationInfo changes that are
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 68869c65..2d9fbf9 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -125,10 +125,13 @@
}
}
+ private static final boolean ENABLE_APK_ASSETS_CACHE = false;
+
/**
* The ApkAssets we are caching and intend to hold strong references to.
*/
- private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(3);
+ private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets =
+ (ENABLE_APK_ASSETS_CACHE) ? new LruCache<>(3) : null;
/**
* The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
@@ -316,9 +319,12 @@
private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay)
throws IOException {
final ApkKey newKey = new ApkKey(path, sharedLib, overlay);
- ApkAssets apkAssets = mLoadedApkAssets.get(newKey);
- if (apkAssets != null) {
- return apkAssets;
+ ApkAssets apkAssets = null;
+ if (mLoadedApkAssets != null) {
+ apkAssets = mLoadedApkAssets.get(newKey);
+ if (apkAssets != null) {
+ return apkAssets;
+ }
}
// Optimistically check if this ApkAssets exists somewhere else.
@@ -326,7 +332,10 @@
if (apkAssetsRef != null) {
apkAssets = apkAssetsRef.get();
if (apkAssets != null) {
- mLoadedApkAssets.put(newKey, apkAssets);
+ if (mLoadedApkAssets != null) {
+ mLoadedApkAssets.put(newKey, apkAssets);
+ }
+
return apkAssets;
} else {
// Clean up the reference.
@@ -341,7 +350,11 @@
} else {
apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib);
}
- mLoadedApkAssets.put(newKey, apkAssets);
+
+ if (mLoadedApkAssets != null) {
+ mLoadedApkAssets.put(newKey, apkAssets);
+ }
+
mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets));
return apkAssets;
}
@@ -441,18 +454,22 @@
pw.println("ResourcesManager:");
pw.increaseIndent();
- pw.print("cached apks: total=");
- pw.print(mLoadedApkAssets.size());
- pw.print(" created=");
- pw.print(mLoadedApkAssets.createCount());
- pw.print(" evicted=");
- pw.print(mLoadedApkAssets.evictionCount());
- pw.print(" hit=");
- pw.print(mLoadedApkAssets.hitCount());
- pw.print(" miss=");
- pw.print(mLoadedApkAssets.missCount());
- pw.print(" max=");
- pw.print(mLoadedApkAssets.maxSize());
+ if (mLoadedApkAssets != null) {
+ pw.print("cached apks: total=");
+ pw.print(mLoadedApkAssets.size());
+ pw.print(" created=");
+ pw.print(mLoadedApkAssets.createCount());
+ pw.print(" evicted=");
+ pw.print(mLoadedApkAssets.evictionCount());
+ pw.print(" hit=");
+ pw.print(mLoadedApkAssets.hitCount());
+ pw.print(" miss=");
+ pw.print(mLoadedApkAssets.missCount());
+ pw.print(" max=");
+ pw.print(mLoadedApkAssets.maxSize());
+ } else {
+ pw.print("cached apks: 0 [cache disabled]");
+ }
pw.println();
pw.print("total apks: ");
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7bcc209..eb8d8d3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3889,6 +3889,11 @@
/**
* Installs the given certificate as a user CA.
+ * <p>
+ * Inserted user CAs aren't automatically trusted by apps in Android 7.0 (API level 24) and
+ * higher. App developers can change the default behavior for an app by adding a
+ * <a href="{@docRoot}training/articles/security-config.html">Security Configuration
+ * File</a> to the app manifest file.
*
* The caller must be a profile or device owner on that user, or a delegate package given the
* {@link #DELEGATION_CERT_INSTALL} scope via {@link #setDelegatedScopes}; otherwise a
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 2a451ff..bcd5f6c 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -76,9 +76,7 @@
* </code></pre>
*
* <h3>Developer guide</h3>
- * To learn more about managing system updates, read
- * <a href="{@docRoot}/work/dpc/security.html#control_remote_software_updates">Control remote
- * software updates</a>.
+ * To learn more, read <a href="{@docRoot}work/dpc/system-updates">Manage system updates</a>.
*
* @see DevicePolicyManager#setSystemUpdatePolicy
* @see DevicePolicyManager#getSystemUpdatePolicy
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index d568662..dd61f28 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -41,18 +41,23 @@
import java.util.List;
/**
- * Assist data automatically created by the platform's implementation of assist and autofill.
+ * <p>This API automatically creates assist data from the platform's
+ * implementation of assist and autofill.
*
* <p>The structure is used for assist purposes when created by
* {@link android.app.Activity#onProvideAssistData}, {@link View#onProvideStructure(ViewStructure)},
* or {@link View#onProvideVirtualStructure(ViewStructure)}.
*
- * <p>The structure is used for autofill purposes when created by
+ * <p>The structure is also used for autofill purposes when created by
* {@link View#onProvideAutofillStructure(ViewStructure, int)},
* or {@link View#onProvideAutofillVirtualStructure(ViewStructure, int)}.
*
- * <p>For performance reasons, some properties of the assist data might be available just for assist
- * or autofill purposes; in those case, the property availability will be document in its javadoc.
+ * <p>For performance reasons, some properties of the assist data might only be available for
+ * assist or autofill purposes. In those cases, a property's availability will be documented
+ * in its javadoc.
+ *
+ * <p>To learn about using Autofill in your app, read the
+ * <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
*/
public class AssistStructure implements Parcelable {
static final String TAG = "AssistStructure";
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
index 7ab3d8b..5694ca8 100644
--- a/core/java/android/appwidget/AppWidgetManagerInternal.java
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -16,12 +16,9 @@
package android.appwidget;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArraySet;
-import java.util.Set;
-
/**
* App widget manager local system service interface.
*
@@ -36,4 +33,13 @@
* @return Whether the UID hosts widgets from the package.
*/
public abstract @Nullable ArraySet<String> getHostedWidgetPackages(int uid);
+
+ /**
+ * Execute the widget-related work of unlocking a user. This is intentionally
+ * invoked just <em>before</em> the boot-completed broadcast is issued, after
+ * the data-related work of unlock has completed.
+ *
+ * @param userId The user that is being unlocked.
+ */
+ public abstract void unlockUser(int userId);
}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 925fa4a..60ac1f0 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -21,7 +21,6 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UserIdInt;
-import android.app.Activity;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
@@ -30,256 +29,23 @@
import android.os.Build.VERSION_CODES;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
/**
- * The ShortcutManager performs operations on an app's set of <em>shortcuts</em>. The
- * {@link ShortcutInfo} class contains information about each of the shortcuts themselves.
+ * <p><code>ShortcutManager</code> executes operations on an app's set of <i>shortcuts</i>, which
+ * represent specific tasks and actions that users can perform within your app. This page lists
+ * components of the <code>ShortcutManager</code> class that you can use to create and manage
+ * sets of shortcuts.
*
- * <p>An app's shortcuts represent specific tasks and actions that users can perform within your
- * app. When a user selects a shortcut in the currently-active launcher, your app opens an activity
- * other than the app's starting activity, provided that the currently-active launcher supports app
- * shortcuts.</p>
+ * <p>To learn about methods that retrieve information about a single shortcut—including
+ * identifiers, type, and status—read the <code>
+ * <a href="/reference/android/content/pm/ShortcutInfo.html">ShortcutInfo</a></code> reference.
*
- * <p>The types of shortcuts that you create for your app depend on the app's key use cases. For
- * example, an email app may publish the "compose new email" shortcut, which allows the app to
- * directly open the compose activity.</p>
- *
- * <p class="note"><b>Note:</b> Only main activities—activities that handle the
- * {@link Intent#ACTION_MAIN} action and the {@link Intent#CATEGORY_LAUNCHER} category—can
- * have shortcuts. If an app has multiple main activities, you need to define the set of shortcuts
- * for <em>each</em> activity.
- *
- * <p>This page discusses the implementation details of the <code>ShortcutManager</code> class. For
- * definitions of key terms and guidance on performing operations on shortcuts within your app, see
- * the <a href="/guide/topics/ui/shortcuts.html">App Shortcuts</a> feature guide.
- *
- * <h3>Shortcut characteristics</h3>
- *
- * This section describes in-depth details about each shortcut type's usage and availability.
- *
- * <p class="note"><b>Important security note:</b> All shortcut information is stored in
- * <a href="/training/articles/direct-boot.html">credential encrypted storage</a>, so your app
- * cannot access a user's shortcuts until after they've unlocked the device.
- *
- * <h4>Static and dynamic shortcuts</h4>
- *
- * <p>Static shortcuts and dynamic shortcuts are shown in a supported launcher when the user
- * performs a specific gesture. On currently-supported launchers, the gesture is a long-press on the
- * app's launcher icon, but the actual gesture may be different on other launcher apps.
- *
- * <p>The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
- *
- * <h4>Pinned shortcuts</h4>
- *
- * <p>Because pinned shortcuts appear in the launcher itself, they're always visible. A pinned
- * shortcut is removed from the launcher only in the following situations:
- * <ul>
- * <li>The user removes it.
- * <li>The publisher app associated with the shortcut is uninstalled.
- * <li>The user selects <b>Clear data</b> from the publisher app's <i>Storage</i> screen, within
- * the system's <b>Settings</b> app.
- * </ul>
- *
- * <p>Because the system performs
- * <a href="/guide/topics/ui/shortcuts.html#backup-and-restore">backup and restore</a> on pinned
- * shortcuts automatically, these shortcuts' IDs should contain either stable, constant strings or
- * server-side identifiers, rather than identifiers generated locally that might not make sense on
- * other devices.
- *
- * <h3>Shortcut display order</h3>
- *
- * <p>When the launcher displays an app's shortcuts, they should appear in the following order:
- *
- * <ol>
- * <li><b>Static shortcuts:</b> Shortcuts whose {@link ShortcutInfo#isDeclaredInManifest()} method
- * returns {@code true}.</li>
- * <li><b>Dynamic shortcuts:</b> Shortcuts whose {@link ShortcutInfo#isDynamic()} method returns
- * {@code true}.</li>
- * </ol>
- *
- * <p>Within each shortcut type (static and dynamic), shortcuts are sorted in order of increasing
- * rank according to {@link ShortcutInfo#getRank()}.</p>
- *
- * <h4>Shortcut ranks</h4>
- *
- * <p>Shortcut ranks are non-negative, sequential integers that determine the order in which
- * shortcuts appear, assuming that the shortcuts are all in the same category. You can update ranks
- * of existing shortcuts when you call {@link #updateShortcuts(List)},
- * {@link #addDynamicShortcuts(List)}, or {@link #setDynamicShortcuts(List)}.
- *
- * <p class="note"><b>Note:</b> Ranks are auto-adjusted so that they're unique for each type of
- * shortcut (static or dynamic). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and
- * 2, adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut
- * at the second position. In response, the third and fourth shortcuts move closer to the bottom of
- * the shortcut list, with their ranks changing to 2 and 3, respectively.
- *
- * <h3>Options for static shortcuts</h3>
- *
- * The following list includes descriptions for the different attributes within a static shortcut.
- * You must provide a value for {@code android:shortcutId} and {@code android:shortcutShortLabel};
- * all other values are optional.
- *
- * <dl>
- * <dt>{@code android:shortcutId}</dt>
- * <dd><p>A string literal, which represents the shortcut when a {@code ShortcutManager} object
- * performs operations on it.</p>
- * <p class="note"><b>Note: </b>You cannot set this attribute's value to a resource string, such
- * as <code>@string/foo</code>.</p>
- * </dd>
- *
- * <dt>{@code android:enabled}</dt>
- * <dd><p>Whether the user can interact with the shortcut from a supported launcher.</p>
- * <p>The default value is {@code true}. If you set it to {@code false}, you should also set
- * {@code android:shortcutDisabledMessage} to a message that explains why you've disabled the
- * shortcut. If you don't think you need to provide such a message, it's easiest to just remove
- * the shortcut from the XML file entirely, rather than changing the values of the shortcut's
- * {@code android:enabled} and {@code android:shortcutDisabledMessage} attributes.
- * </dd>
- *
- * <dt>{@code android:icon}</dt>
- * <dd><p>The <a href="/topic/performance/graphics/index.html">bitmap</a> or
- * <a href="/guide/practices/ui_guidelines/icon_design_adaptive.html">adaptive icon</a> that the
- * launcher uses when displaying the shortcut to the user. This value can be either the path to an
- * image or the resource file that contains the image. Use adaptive icons whenever possible to
- * improve performance and consistency.</p>
- * <p class="note"><b>Note: </b>Shortcut icons cannot include
- * <a href="/training/material/drawables.html#DrawableTint">tints</a>.
- * </dd>
- *
- * <dt>{@code android:shortcutShortLabel}</dt>
- * <dd><p>A concise phrase that describes the shortcut's purpose. For more information, see
- * {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</p>
- * <p class="note"><b>Note: </b>This attribute's value must be a resource string, such as
- * <code>@string/shortcut_short_label</code>.</p>
- * </dd>
- *
- * <dt>{@code android:shortcutLongLabel}</dt>
- * <dd><p>An extended phrase that describes the shortcut's purpose. If there's enough space, the
- * launcher displays this value instead of {@code android:shortcutShortLabel}. For more
- * information, see {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</p>
- * <p class="note"><b>Note: </b>This attribute's value must be a resource string, such as
- * <code>@string/shortcut_long_label</code>.</p>
- * </dd>
- *
- * <dt>{@code android:shortcutDisabledMessage}</dt>
- * <dd><p>The message that appears in a supported launcher when the user attempts to launch a
- * disabled shortcut. The message should explain to the user why the shortcut is now disabled.
- * This attribute's value has no effect if {@code android:enabled} is {@code true}.</p>
- * <p class="note"><b>Note: </b>This attribute's value must be a resource string, such as
- * <code>@string/shortcut_disabled_message</code>.</p>
- * </dd>
- * </dl>
- *
- * <h3>Inner elements that define static shortcuts</h3>
- *
- * <p>The XML file that lists an app's static shortcuts supports the following elements inside each
- * {@code <shortcut>} element. You must include an {@code intent} inner element for each
- * static shortcut that you define.</p>
- *
- * <dl>
- * <dt>{@code intent}</dt>
- * <dd><p>The action that the system launches when the user selects the shortcut. This intent must
- * provide a value for the {@code android:action} attribute.</p>
- * <p>You can provide multiple intents for a single shortcut. If you do so, the last defined
- * activity is launched, and the other activities are placed in the
- * <a href="/guide/components/tasks-and-back-stack.html">back stack</a>. See
- * <a href="/guide/topics/ui/shortcuts.html#static">Using Static Shortcuts</a> and the
- * {@link android.app.TaskStackBuilder} class reference for details.</p>
- * <p class="note"><b>Note:</b> This {@code intent} element cannot include string resources.</p>
- * <p>To learn more about how to configure intents, see
- * <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a>.</p>
- * </dd>
- *
- * <dt>{@code categories}</dt>
- * <dd><p>Provides a grouping for the types of actions that your app's shortcuts perform, such as
- * creating new chat messages.</p>
- * <p>For a list of supported shortcut categories, see the {@link ShortcutInfo} class reference
- * for a list of supported shortcut categories.
- * </dd>
- * </dl>
- *
- * <h3>Updating shortcuts</h3>
- *
- * <p>Each app's launcher icon can contain at most {@link #getMaxShortcutCountPerActivity()} number
- * of static and dynamic shortcuts combined. There is no limit to the number of pinned shortcuts
- * that an app can create, though.
- *
- * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
- * the pinned shortcut is still visible and launchable. This allows an app to have more than
- * {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
- *
- * <p>As an example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
- * <ol>
- * <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
- * conversations (c1, c2, ..., c5).
- *
- * <li>The user pins all 5 of the shortcuts.
- *
- * <li>Later, the user has started 3 additional conversations (c6, c7, and c8), so the publisher
- * app re-publishes its dynamic shortcuts. The new dynamic shortcut list is: c4, c5, ..., c8.
- * <p>The publisher app has to remove c1, c2, and c3 because it can't have more than 5 dynamic
- * shortcuts. However, c1, c2, and c3 are still pinned shortcuts that the user can access and
- * launch.
- * <p>At this point, the user can access a total of 8 shortcuts that link to activities in the
- * publisher app, including the 3 pinned shortcuts, even though an app can have at most 5
- * dynamic shortcuts.
- *
- * <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
- * 8 shortcuts, when, for example, the chat peers' icons have changed.
- * <p>The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
- * can also be used to update existing shortcuts with the same IDs, but they <b>cannot</b> be
- * used for updating non-dynamic, pinned shortcuts because these 2 methods try to convert the
- * given lists of shortcuts to dynamic shortcuts.
- * </ol>
- *
- * <h3>Shortcut intents</h3>
- *
- * <p>
- * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags.
- * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other
- * flags; otherwise, if the app is already running, the app is simply brought to
- * the foreground, and the target activity might not appear.
- *
- * <p>Static shortcuts <b>cannot</b> have custom intent flags.
- * The first intent of a static shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
- * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set. This means, when the app is already running, all
- * the existing activities in your app are destroyed when a static shortcut is launched.
- * If this behavior is not desirable, you can use a <em>trampoline activity</em>, or an invisible
- * activity that starts another activity in {@link Activity#onCreate}, then calls
- * {@link Activity#finish()}:
- * <ol>
- * <li>In the <code>AndroidManifest.xml</code> file, the trampoline activity should include the
- * attribute assignment {@code android:taskAffinity=""}.
- * <li>In the shortcuts resource file, the intent within the static shortcut should reference
- * the trampoline activity.
- * </ol>
- *
- * <h3>Rate limiting</h3>
- *
- * <p>When <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is active,
- * {@link #isRateLimitingActive()} returns {@code true}.
- *
- * <p>Rate limiting is reset upon certain events, so even background apps can call these APIs until
- * the rate limit is reached again. These events include the following:
- * <ul>
- * <li>An app comes to the foreground.
- * <li>The system locale changes.
- * <li>The user performs the <a href="/guide/topics/ui/notifiers/notifications.html#direct">inline
- * reply</a> action on a notification.
- * </ul>
- *
- * <h3>Handling system locale changes</h3>
- *
- * <p>Apps should update dynamic and pinned shortcuts when they receive the
- * {@link Intent#ACTION_LOCALE_CHANGED} broadcast, indicating that the system locale has changed.
- * <p>When the system locale changes, <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate
- * limiting</a> is reset, so even background apps can add and update dynamic shortcuts until the
- * rate limit is reached again.
+ * <p>For guidance about using shortcuts, see
+ * <a href="/guide/topics/ui/shortcuts/index.html">App shortcuts</a>.
*
* <h3>Retrieving class instances</h3>
* <!-- Provides a heading for the content filled in by the @SystemService annotation below -->
@@ -460,8 +226,9 @@
}
/**
- * Disable pinned shortcuts. For more details, see the Javadoc for the {@link ShortcutManager}
- * class.
+ * Disable pinned shortcuts. For more details, read
+ * <a href="/guide/topics/ui/shortcuts/managing-shortcuts.html#disable-shortcuts">
+ * Disable shortcuts</a>.
*
* @throws IllegalArgumentException If trying to disable immutable shortcuts.
*
@@ -500,7 +267,9 @@
/**
* Disable pinned shortcuts, showing the user a custom error message when they try to select
* the disabled shortcuts.
- * For more details, see the Javadoc for the {@link ShortcutManager} class.
+ * For more details, read
+ * <a href="/guide/topics/ui/shortcuts/managing-shortcuts.html#disable-shortcuts">
+ * Disable shortcuts</a>.
*
* @throws IllegalArgumentException If trying to disable immutable shortcuts.
*
@@ -588,7 +357,8 @@
/**
* Return {@code true} when rate-limiting is active for the caller app.
*
- * <p>See the class level javadoc for details.
+ * <p>For details, see <a href="/guide/topics/ui/shortcuts/managing-shortcuts#rate-limiting">
+ * Rate limiting</a>.
*
* @throws IllegalStateException when the user is locked.
*/
@@ -634,7 +404,9 @@
* Apps that publish shortcuts should call this method whenever the user
* selects the shortcut containing the given ID or when the user completes
* an action in the app that is equivalent to selecting the shortcut.
- * For more details, see the Javadoc for the {@link ShortcutManager} class
+ * For more details, read about
+ * <a href="/guide/topics/ui/shortcuts/managing-shortcuts.html#track-usage">
+ * tracking shortcut usage</a>.
*
* <p>The information is accessible via {@link UsageStatsManager#queryEvents}
* Typically, launcher apps use this information to build a prediction model
@@ -702,7 +474,9 @@
* @param resultIntent If not null, this intent will be sent when the shortcut is pinned.
* Use {@link android.app.PendingIntent#getIntentSender()} to create an {@link IntentSender}.
* To avoid background execution limits, use an unexported, manifest-declared receiver.
- * For more details, see the overview documentation for the {@link ShortcutManager} class.
+ * For more details, see
+ * <a href="/guide/topics/ui/shortcuts/creating-shortcuts.html#pinned">
+ * Creating pinned shortcuts</a>.
*
* @return {@code TRUE} if the launcher supports this feature. Note the API will return without
* waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 424da76..25d98f7 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1757,7 +1757,8 @@
executeSql(sql, bindArgs);
}
- private int executeSql(String sql, Object[] bindArgs) throws SQLException {
+ /** {@hide} */
+ public int executeSql(String sql, Object[] bindArgs) throws SQLException {
acquireReference();
try {
final int statementType = DatabaseUtils.getSqlStatementType(sql);
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 1bd44fa..a984200 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -16,18 +16,26 @@
package android.database.sqlite;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.content.ContentValues;
import android.database.Cursor;
import android.database.DatabaseUtils;
+import android.os.Build;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
+import libcore.util.EmptyArray;
+
+import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
@@ -99,9 +107,6 @@
if (mWhereClause == null) {
mWhereClause = new StringBuilder(inWhere.length() + 16);
}
- if (mWhereClause.length() == 0) {
- mWhereClause.append('(');
- }
mWhereClause.append(inWhere);
}
@@ -119,9 +124,6 @@
if (mWhereClause == null) {
mWhereClause = new StringBuilder(inWhere.length() + 16);
}
- if (mWhereClause.length() == 0) {
- mWhereClause.append('(');
- }
DatabaseUtils.appendEscapedSQLString(mWhereClause, inWhere);
}
@@ -380,6 +382,11 @@
return null;
}
+ final String sql;
+ final String unwrappedSql = buildQuery(
+ projectionIn, selection, groupBy, having,
+ sortOrder, limit);
+
if (mStrict && selection != null && selection.length() > 0) {
// Validate the user-supplied selection to detect syntactic anomalies
// in the selection string that could indicate a SQL injection attempt.
@@ -388,25 +395,167 @@
// originally specified. An attacker cannot create an expression that
// would escape the SQL expression while maintaining balanced parentheses
// in both the wrapped and original forms.
- String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
+
+ // NOTE: The ordering of the below operations is important; we must
+ // execute the wrapped query to ensure the untrusted clause has been
+ // fully isolated.
+
+ // Validate the unwrapped query
+ db.validateSql(unwrappedSql, cancellationSignal); // will throw if query is invalid
+
+ // Execute wrapped query for extra protection
+ final String wrappedSql = buildQuery(projectionIn, wrap(selection), groupBy,
having, sortOrder, limit);
- db.validateSql(sqlForValidation, cancellationSignal); // will throw if query is invalid
+ sql = wrappedSql;
+ } else {
+ // Execute unwrapped query
+ sql = unwrappedSql;
}
- String sql = buildQuery(
- projectionIn, selection, groupBy, having,
- sortOrder, limit);
-
+ final String[] sqlArgs = selectionArgs;
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Performing query: " + sql);
+ if (Build.IS_DEBUGGABLE) {
+ Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
+ } else {
+ Log.d(TAG, sql);
+ }
}
return db.rawQueryWithFactory(
- mFactory, sql, selectionArgs,
+ mFactory, sql, sqlArgs,
SQLiteDatabase.findEditTable(mTables),
cancellationSignal); // will throw if query is invalid
}
/**
+ * Perform an update by combining all current settings and the
+ * information passed into this method.
+ *
+ * @param db the database to update on
+ * @param selection A filter declaring which rows to return,
+ * formatted as an SQL WHERE clause (excluding the WHERE
+ * itself). Passing null will return all rows for the given URL.
+ * @param selectionArgs You may include ?s in selection, which
+ * will be replaced by the values from selectionArgs, in order
+ * that they appear in the selection. The values will be bound
+ * as Strings.
+ * @return the number of rows updated
+ * @hide
+ */
+ public int update(@NonNull SQLiteDatabase db, @NonNull ContentValues values,
+ @Nullable String selection, @Nullable String[] selectionArgs) {
+ Objects.requireNonNull(mTables, "No tables defined");
+ Objects.requireNonNull(db, "No database defined");
+ Objects.requireNonNull(values, "No values defined");
+
+ final String sql;
+ final String unwrappedSql = buildUpdate(values, selection);
+
+ if (mStrict) {
+ // Validate the user-supplied selection to detect syntactic anomalies
+ // in the selection string that could indicate a SQL injection attempt.
+ // The idea is to ensure that the selection clause is a valid SQL expression
+ // by compiling it twice: once wrapped in parentheses and once as
+ // originally specified. An attacker cannot create an expression that
+ // would escape the SQL expression while maintaining balanced parentheses
+ // in both the wrapped and original forms.
+
+ // NOTE: The ordering of the below operations is important; we must
+ // execute the wrapped query to ensure the untrusted clause has been
+ // fully isolated.
+
+ // Validate the unwrapped query
+ db.validateSql(unwrappedSql, null); // will throw if query is invalid
+
+ // Execute wrapped query for extra protection
+ final String wrappedSql = buildUpdate(values, wrap(selection));
+ sql = wrappedSql;
+ } else {
+ // Execute unwrapped query
+ sql = unwrappedSql;
+ }
+
+ if (selectionArgs == null) {
+ selectionArgs = EmptyArray.STRING;
+ }
+ final String[] rawKeys = values.keySet().toArray(EmptyArray.STRING);
+ final int valuesLength = rawKeys.length;
+ final Object[] sqlArgs = new Object[valuesLength + selectionArgs.length];
+ for (int i = 0; i < sqlArgs.length; i++) {
+ if (i < valuesLength) {
+ sqlArgs[i] = values.get(rawKeys[i]);
+ } else {
+ sqlArgs[i] = selectionArgs[i - valuesLength];
+ }
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ if (Build.IS_DEBUGGABLE) {
+ Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
+ } else {
+ Log.d(TAG, sql);
+ }
+ }
+ return db.executeSql(sql, sqlArgs);
+ }
+
+ /**
+ * Perform a delete by combining all current settings and the
+ * information passed into this method.
+ *
+ * @param db the database to delete on
+ * @param selection A filter declaring which rows to return,
+ * formatted as an SQL WHERE clause (excluding the WHERE
+ * itself). Passing null will return all rows for the given URL.
+ * @param selectionArgs You may include ?s in selection, which
+ * will be replaced by the values from selectionArgs, in order
+ * that they appear in the selection. The values will be bound
+ * as Strings.
+ * @return the number of rows deleted
+ * @hide
+ */
+ public int delete(@NonNull SQLiteDatabase db, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ Objects.requireNonNull(mTables, "No tables defined");
+ Objects.requireNonNull(db, "No database defined");
+
+ final String sql;
+ final String unwrappedSql = buildDelete(selection);
+
+ if (mStrict) {
+ // Validate the user-supplied selection to detect syntactic anomalies
+ // in the selection string that could indicate a SQL injection attempt.
+ // The idea is to ensure that the selection clause is a valid SQL expression
+ // by compiling it twice: once wrapped in parentheses and once as
+ // originally specified. An attacker cannot create an expression that
+ // would escape the SQL expression while maintaining balanced parentheses
+ // in both the wrapped and original forms.
+
+ // NOTE: The ordering of the below operations is important; we must
+ // execute the wrapped query to ensure the untrusted clause has been
+ // fully isolated.
+
+ // Validate the unwrapped query
+ db.validateSql(unwrappedSql, null); // will throw if query is invalid
+
+ // Execute wrapped query for extra protection
+ final String wrappedSql = buildDelete(wrap(selection));
+ sql = wrappedSql;
+ } else {
+ // Execute unwrapped query
+ sql = unwrappedSql;
+ }
+
+ final String[] sqlArgs = selectionArgs;
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ if (Build.IS_DEBUGGABLE) {
+ Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
+ } else {
+ Log.d(TAG, sql);
+ }
+ }
+ return db.executeSql(sql, sqlArgs);
+ }
+
+ /**
* Construct a SELECT statement suitable for use in a group of
* SELECT statements that will be joined through UNION operators
* in buildUnionQuery.
@@ -438,28 +587,10 @@
String[] projectionIn, String selection, String groupBy,
String having, String sortOrder, String limit) {
String[] projection = computeProjection(projectionIn);
-
- StringBuilder where = new StringBuilder();
- boolean hasBaseWhereClause = mWhereClause != null && mWhereClause.length() > 0;
-
- if (hasBaseWhereClause) {
- where.append(mWhereClause.toString());
- where.append(')');
- }
-
- // Tack on the user's selection, if present.
- if (selection != null && selection.length() > 0) {
- if (hasBaseWhereClause) {
- where.append(" AND ");
- }
-
- where.append('(');
- where.append(selection);
- where.append(')');
- }
+ String where = computeWhere(selection);
return buildQueryString(
- mDistinct, mTables, projection, where.toString(),
+ mDistinct, mTables, projection, where,
groupBy, having, sortOrder, limit);
}
@@ -476,6 +607,42 @@
return buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit);
}
+ /** {@hide} */
+ public String buildUpdate(ContentValues values, String selection) {
+ if (values == null || values.size() == 0) {
+ throw new IllegalArgumentException("Empty values");
+ }
+
+ StringBuilder sql = new StringBuilder(120);
+ sql.append("UPDATE ");
+ sql.append(mTables);
+ sql.append(" SET ");
+
+ final String[] rawKeys = values.keySet().toArray(EmptyArray.STRING);
+ for (int i = 0; i < rawKeys.length; i++) {
+ if (i > 0) {
+ sql.append(',');
+ }
+ sql.append(rawKeys[i]);
+ sql.append("=?");
+ }
+
+ final String where = computeWhere(selection);
+ appendClause(sql, " WHERE ", where);
+ return sql.toString();
+ }
+
+ /** {@hide} */
+ public String buildDelete(String selection) {
+ StringBuilder sql = new StringBuilder(120);
+ sql.append("DELETE FROM ");
+ sql.append(mTables);
+
+ final String where = computeWhere(selection);
+ appendClause(sql, " WHERE ", where);
+ return sql.toString();
+ }
+
/**
* Construct a SELECT statement suitable for use in a group of
* SELECT statements that will be joined through UNION operators
@@ -650,4 +817,37 @@
}
return null;
}
+
+ private @Nullable String computeWhere(@Nullable String selection) {
+ final boolean hasInternal = !TextUtils.isEmpty(mWhereClause);
+ final boolean hasExternal = !TextUtils.isEmpty(selection);
+
+ if (hasInternal || hasExternal) {
+ final StringBuilder where = new StringBuilder();
+ if (hasInternal) {
+ where.append('(').append(mWhereClause).append(')');
+ }
+ if (hasInternal && hasExternal) {
+ where.append(" AND ");
+ }
+ if (hasExternal) {
+ where.append('(').append(selection).append(')');
+ }
+ return where.toString();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Wrap given argument in parenthesis, unless it's {@code null} or
+ * {@code ()}, in which case return it verbatim.
+ */
+ private @Nullable String wrap(@Nullable String arg) {
+ if (TextUtils.isEmpty(arg)) {
+ return arg;
+ } else {
+ return "(" + arg + ")";
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 9b18e9a..35584ae 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1255,7 +1255,9 @@
* <p>If this device is the largest or only camera device with a given facing, then this
* position will be <code>(0, 0, 0)</code>; a camera device with a lens optical center located 3 cm
* from the main sensor along the +X axis (to the right from the user's perspective) will
- * report <code>(0.03, 0, 0)</code>.</p>
+ * report <code>(0.03, 0, 0)</code>. Note that this means that, for many computer vision
+ * applications, the position needs to be negated to convert it to a translation from the
+ * camera to the origin.</p>
* <p>To transform a pixel coordinates between two cameras facing the same direction, first
* the source camera {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} must be corrected for. Then the source
* camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the
@@ -1267,7 +1269,8 @@
* <p>To compare this against a real image from the destination camera, the destination camera
* image then needs to be corrected for radial distortion before comparison or sampling.</p>
* <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
- * the center of the primary gyroscope on the device.</p>
+ * the center of the primary gyroscope on the device. The axis definitions are the same as
+ * with PRIMARY_CAMERA.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
@@ -1299,13 +1302,15 @@
* </code></pre>
* <p>which can then be combined with the camera pose rotation
* <code>R</code> and translation <code>t</code> ({@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} and
- * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, respective) to calculate the
+ * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, respectively) to calculate the
* complete transform from world coordinates to pixel
* coordinates:</p>
- * <pre><code>P = [ K 0 * [ R t
- * 0 1 ] 0 1 ]
+ * <pre><code>P = [ K 0 * [ R -Rt
+ * 0 1 ] 0 1 ]
* </code></pre>
- * <p>and with <code>p_w</code> being a point in the world coordinate system
+ * <p>(Note the negation of poseTranslation when mapping from camera
+ * to world coordinates, and multiplication by the rotation).</p>
+ * <p>With <code>p_w</code> being a point in the world coordinate system
* and <code>p_s</code> being a point in the camera active pixel array
* coordinate system, and with the mapping including the
* homogeneous division by z:</p>
@@ -1327,6 +1332,13 @@
* activeArraySize rectangle), to determine the final pixel
* coordinate of the world point for processed (non-RAW)
* output buffers.</p>
+ * <p>For camera devices, the center of pixel <code>(x,y)</code> is located at
+ * coordinate <code>(x + 0.5, y + 0.5)</code>. So on a device with a
+ * precorrection active array of size <code>(10,10)</code>, the valid pixel
+ * indices go from <code>(0,0)-(9,9)</code>, and an perfectly-built camera would
+ * have an optical center at the exact center of the pixel grid, at
+ * coordinates <code>(5.0, 5.0)</code>, which is the top-left corner of pixel
+ * <code>(5,5)</code>.</p>
* <p><b>Units</b>:
* Pixels in the
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1275a85..caa99d5 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -819,11 +819,11 @@
* camera in the list of supported camera devices.</p>
* <p>This capability requires the camera device to support the following:</p>
* <ul>
- * <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
- * <li>android.logicalMultiCamera.physicalIds</li>
- * <li>{@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType}</li>
- * </ul>
- * </li>
+ * <li>The IDs of underlying physical cameras are returned via
+ * {@link android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds }.</li>
+ * <li>This camera device must list static metadata
+ * {@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType} in
+ * {@link android.hardware.camera2.CameraCharacteristics }.</li>
* <li>The underlying physical cameras' static metadata must list the following entries,
* so that the application can correlate pixels from the physical streams:<ul>
* <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 0b92b0c..4a20468 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2530,7 +2530,7 @@
* outputs will crop horizontally (pillarbox), and 16:9
* streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+ * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, the width and height
* of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
* <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
@@ -2871,8 +2871,14 @@
new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
/**
- * <p>A control for selecting whether OIS position information is included in output
- * result metadata.</p>
+ * <p>A control for selecting whether optical stabilization (OIS) position
+ * information is included in output result metadata.</p>
+ * <p>Since optical image stabilization generally involves motion much faster than the duration
+ * of individualq image exposure, multiple OIS samples can be included for a single capture
+ * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
+ * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
+ * with the rolling shutter skew to account for lens motion during image exposure in
+ * post-processing algorithms.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
@@ -3272,14 +3278,28 @@
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
* <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output. Metadata coordinates such as face rectangles or metering
- * regions are also not affected by correction.</p>
+ * applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
* metadata coordinates follow the coordinate system of
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata
- * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+ * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. The
+ * camera device will map these metadata fields to match the corrected image produced by the
+ * camera device, for both capture requests and results. However, this mapping is not very
+ * precise, since rectangles do not generally map to rectangles when corrected. Only linear
+ * scaling between the active array and precorrection active array coordinates is
+ * performed. Applications that require precise correction of metadata need to undo that
+ * linear scaling, and apply a more complete correction that takes into the account the app's
+ * own requirements.</p>
+ * <p>The full list of metadata that is affected in this way by distortion correction is:</p>
+ * <ul>
+ * <li>{@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}</li>
+ * <li>{@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}</li>
+ * <li>{@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}</li>
+ * <li>{@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}</li>
+ * <li>{@link CaptureResult#STATISTICS_FACES android.statistics.faces}</li>
+ * </ul>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
@@ -3290,10 +3310,15 @@
* {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CaptureRequest#CONTROL_AE_REGIONS
+ * @see CaptureRequest#CONTROL_AF_REGIONS
+ * @see CaptureRequest#CONTROL_AWB_REGIONS
* @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
* @see CameraCharacteristics#LENS_DISTORTION
+ * @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see CaptureResult#STATISTICS_FACES
* @see #DISTORTION_CORRECTION_MODE_OFF
* @see #DISTORTION_CORRECTION_MODE_FAST
* @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index e007d28..1e894e8 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2858,7 +2858,9 @@
* <p>If this device is the largest or only camera device with a given facing, then this
* position will be <code>(0, 0, 0)</code>; a camera device with a lens optical center located 3 cm
* from the main sensor along the +X axis (to the right from the user's perspective) will
- * report <code>(0.03, 0, 0)</code>.</p>
+ * report <code>(0.03, 0, 0)</code>. Note that this means that, for many computer vision
+ * applications, the position needs to be negated to convert it to a translation from the
+ * camera to the origin.</p>
* <p>To transform a pixel coordinates between two cameras facing the same direction, first
* the source camera {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} must be corrected for. Then the source
* camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the
@@ -2870,7 +2872,8 @@
* <p>To compare this against a real image from the destination camera, the destination camera
* image then needs to be corrected for radial distortion before comparison or sampling.</p>
* <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
- * the center of the primary gyroscope on the device.</p>
+ * the center of the primary gyroscope on the device. The axis definitions are the same as
+ * with PRIMARY_CAMERA.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
@@ -2902,13 +2905,15 @@
* </code></pre>
* <p>which can then be combined with the camera pose rotation
* <code>R</code> and translation <code>t</code> ({@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} and
- * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, respective) to calculate the
+ * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, respectively) to calculate the
* complete transform from world coordinates to pixel
* coordinates:</p>
- * <pre><code>P = [ K 0 * [ R t
- * 0 1 ] 0 1 ]
+ * <pre><code>P = [ K 0 * [ R -Rt
+ * 0 1 ] 0 1 ]
* </code></pre>
- * <p>and with <code>p_w</code> being a point in the world coordinate system
+ * <p>(Note the negation of poseTranslation when mapping from camera
+ * to world coordinates, and multiplication by the rotation).</p>
+ * <p>With <code>p_w</code> being a point in the world coordinate system
* and <code>p_s</code> being a point in the camera active pixel array
* coordinate system, and with the mapping including the
* homogeneous division by z:</p>
@@ -2930,6 +2935,13 @@
* activeArraySize rectangle), to determine the final pixel
* coordinate of the world point for processed (non-RAW)
* output buffers.</p>
+ * <p>For camera devices, the center of pixel <code>(x,y)</code> is located at
+ * coordinate <code>(x + 0.5, y + 0.5)</code>. So on a device with a
+ * precorrection active array of size <code>(10,10)</code>, the valid pixel
+ * indices go from <code>(0,0)-(9,9)</code>, and an perfectly-built camera would
+ * have an optical center at the exact center of the pixel grid, at
+ * coordinates <code>(5.0, 5.0)</code>, which is the top-left corner of pixel
+ * <code>(5,5)</code>.</p>
* <p><b>Units</b>:
* Pixels in the
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
@@ -3194,7 +3206,7 @@
* outputs will crop horizontally (pillarbox), and 16:9
* streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+ * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, the width and height
* of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
* <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
@@ -4083,8 +4095,14 @@
new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
/**
- * <p>A control for selecting whether OIS position information is included in output
- * result metadata.</p>
+ * <p>A control for selecting whether optical stabilization (OIS) position
+ * information is included in output result metadata.</p>
+ * <p>Since optical image stabilization generally involves motion much faster than the duration
+ * of individualq image exposure, multiple OIS samples can be included for a single capture
+ * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
+ * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
+ * with the rolling shutter skew to account for lens motion during image exposure in
+ * post-processing algorithms.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
@@ -4118,11 +4136,15 @@
/**
* <p>An array of shifts of OIS samples, in x direction.</p>
* <p>The array contains the amount of shifts in x direction, in pixels, based on OIS samples.
- * A positive value is a shift from left to right in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, a shift of
- * (3, 0) puts the new optical center at (1003, 500).</p>
+ * A positive value is a shift from left to right in the pre-correction active array
+ * coordinate system. For example, if the optical center is (1000, 500) in pre-correction
+ * active array coordinates, a shift of (3, 0) puts the new optical center at (1003, 500).</p>
* <p>The number of shifts must match the number of timestamps in
* android.statistics.oisTimestamps.</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
* <p><b>Units</b>: Pixels in active array.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @hide
@@ -4133,11 +4155,15 @@
/**
* <p>An array of shifts of OIS samples, in y direction.</p>
* <p>The array contains the amount of shifts in y direction, in pixels, based on OIS samples.
- * A positive value is a shift from top to bottom in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, a shift of
- * (0, 5) puts the new optical center at (1000, 505).</p>
+ * A positive value is a shift from top to bottom in pre-correction active array coordinate
+ * system. For example, if the optical center is (1000, 500) in active array coordinates, a
+ * shift of (0, 5) puts the new optical center at (1000, 505).</p>
* <p>The number of shifts must match the number of timestamps in
* android.statistics.oisTimestamps.</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
* <p><b>Units</b>: Pixels in active array.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @hide
@@ -4146,15 +4172,21 @@
new Key<float[]>("android.statistics.oisYShifts", float[].class);
/**
- * <p>An array of OIS samples.</p>
+ * <p>An array of optical stabilization (OIS) position samples.</p>
* <p>Each OIS sample contains the timestamp and the amount of shifts in x and y direction,
* in pixels, of the OIS sample.</p>
- * <p>A positive value for a shift in x direction is a shift from left to right in active array
- * coordinate system. For example, if the optical center is (1000, 500) in active array
- * coordinates, a shift of (3, 0) puts the new optical center at (1003, 500).</p>
- * <p>A positive value for a shift in y direction is a shift from top to bottom in active array
- * coordinate system. For example, if the optical center is (1000, 500) in active array
- * coordinates, a shift of (0, 5) puts the new optical center at (1000, 505).</p>
+ * <p>A positive value for a shift in x direction is a shift from left to right in the
+ * pre-correction active array coordinate system. For example, if the optical center is
+ * (1000, 500) in pre-correction active array coordinates, a shift of (3, 0) puts the new
+ * optical center at (1003, 500).</p>
+ * <p>A positive value for a shift in y direction is a shift from top to bottom in
+ * pre-correction active array coordinate system. For example, if the optical center is
+ * (1000, 500) in active array coordinates, a shift of (0, 5) puts the new optical center at
+ * (1000, 505).</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*/
@PublicKey
@@ -4584,14 +4616,28 @@
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
* <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output. Metadata coordinates such as face rectangles or metering
- * regions are also not affected by correction.</p>
+ * applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
* metadata coordinates follow the coordinate system of
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata
- * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+ * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. The
+ * camera device will map these metadata fields to match the corrected image produced by the
+ * camera device, for both capture requests and results. However, this mapping is not very
+ * precise, since rectangles do not generally map to rectangles when corrected. Only linear
+ * scaling between the active array and precorrection active array coordinates is
+ * performed. Applications that require precise correction of metadata need to undo that
+ * linear scaling, and apply a more complete correction that takes into the account the app's
+ * own requirements.</p>
+ * <p>The full list of metadata that is affected in this way by distortion correction is:</p>
+ * <ul>
+ * <li>{@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}</li>
+ * <li>{@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}</li>
+ * <li>{@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}</li>
+ * <li>{@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}</li>
+ * <li>{@link CaptureResult#STATISTICS_FACES android.statistics.faces}</li>
+ * </ul>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
@@ -4602,10 +4648,15 @@
* {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CaptureRequest#CONTROL_AE_REGIONS
+ * @see CaptureRequest#CONTROL_AF_REGIONS
+ * @see CaptureRequest#CONTROL_AWB_REGIONS
* @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
* @see CameraCharacteristics#LENS_DISTORTION
+ * @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see CaptureResult#STATISTICS_FACES
* @see #DISTORTION_CORRECTION_MODE_OFF
* @see #DISTORTION_CORRECTION_MODE_FAST
* @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 1b22911..22dd4fc 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -333,6 +333,14 @@
/**
* Remove any statistics parameters from the given {@link Socket}.
+ * <p>
+ * In Android 8.1 (API level 27) and lower, a socket is automatically
+ * untagged when it's sent to another process using binder IPC with a
+ * {@code ParcelFileDescriptor} container. In Android 9.0 (API level 28)
+ * and higher, the socket tag is kept when the socket is sent to another
+ * process using binder IPC. You can mimic the previous behavior by
+ * calling {@code untagSocket()} before sending the socket to another
+ * process.
*/
public static void untagSocket(Socket socket) throws SocketException {
SocketTagger.get().untag(socket);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9188894..68b6d72 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -628,7 +628,8 @@
* October 2013: Android 4.4, KitKat, another tasty treat.
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see the
+ * <a href="/about/versions/kitkat/">Android KitKat overview</a>.</p>
* <ul>
* <li> The default result of
* {@link android.preference.PreferenceActivity#isValidFragment(String)
@@ -678,7 +679,8 @@
* November 2014: Lollipop. A flat one with beautiful shadows. But still tasty.
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see the
+ * <a href="/about/versions/lollipop/">Android Lollipop overview</a>.</p>
* <ul>
* <li> {@link android.content.Context#bindService Context.bindService} now
* requires an explicit Intent, and will throw an exception if given an implicit
@@ -707,6 +709,8 @@
/**
* March 2015: Lollipop with an extra sugar coating on the outside!
+ * For more information about this release, see the
+ * <a href="/about/versions/android-5.1">Android 5.1 APIs</a>.
*/
public static final int LOLLIPOP_MR1 = 22;
@@ -714,7 +718,8 @@
* M is for Marshmallow!
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see the
+ * <a href="/about/versions/marshmallow/">Android 6.0 Marshmallow overview</a>.</p>
* <ul>
* <li> Runtime permissions. Dangerous permissions are no longer granted at
* install time, but must be requested by the application at runtime through
@@ -745,7 +750,8 @@
* N is for Nougat.
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see
+ * the <a href="/about/versions/nougat/">Android Nougat overview</a>.</p>
* <ul>
* <li> {@link android.app.DownloadManager.Request#setAllowedNetworkTypes
* DownloadManager.Request.setAllowedNetworkTypes}
@@ -795,7 +801,9 @@
public static final int N = 24;
/**
- * N MR1: Nougat++.
+ * N MR1: Nougat++. For more information about this release, see
+ * <a href="/about/versions/nougat/android-7.1">Android 7.1 for
+ * Developers</a>.
*/
public static final int N_MR1 = 25;
@@ -803,7 +811,8 @@
* O.
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see
+ * the <a href="/about/versions/oreo/">Android Oreo overview</a>.</p>
* <ul>
* <li><a href="{@docRoot}about/versions/oreo/background.html">Background execution limits</a>
* are applied to the application.</li>
@@ -892,13 +901,16 @@
* O MR1.
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see
+ * <a href="/about/versions/oreo/android-8.1">Android 8.1 features and
+ * APIs</a>.</p>
* <ul>
* <li>Apps exporting and linking to apk shared libraries must explicitly
* enumerate all signing certificates in a consistent order.</li>
* <li>{@link android.R.attr#screenOrientation} can not be used to request a fixed
* orientation if the associated activity is not fullscreen and opaque.</li>
* </ul>
+ *
*/
public static final int O_MR1 = 27;
@@ -906,7 +918,8 @@
* P.
*
* <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
+ * new changes in behavior. For more information about this release, see the
+ * <a href="/about/versions/pie/">Android 9 Pie overview</a>.</p>
* <ul>
* <li>{@link android.app.Service#startForeground Service.startForeground} requires
* that apps hold the permission
@@ -914,6 +927,7 @@
* <li>{@link android.widget.LinearLayout} will always remeasure weighted children,
* even if there is no excess space.</li>
* </ul>
+ *
*/
public static final int P = 28;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index b303e10..455d8ed 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -349,7 +349,7 @@
}
/**
- * Retrieve the a {@link android.os.Handler Handler} implementation that
+ * Retrieve the {@link android.os.Handler Handler} implementation that
* will receive this message. The object must implement
* {@link android.os.Handler#handleMessage(android.os.Message)
* Handler.handleMessage()}. Each Handler has its own name-space for
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index d4d3dc8..7b3ea57 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -65,11 +65,17 @@
public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new
Parcelable.Creator<StatsLogEventWrapper>() {
public StatsLogEventWrapper createFromParcel(Parcel in) {
- return new StatsLogEventWrapper(in);
+ android.util.EventLog.writeEvent(0x534e4554, "112550251",
+ android.os.Binder.getCallingUid(), "");
+ // Purposefully leaving this method not implemented.
+ throw new RuntimeException("Not implemented");
}
public StatsLogEventWrapper[] newArray(int size) {
- return new StatsLogEventWrapper[size];
+ android.util.EventLog.writeEvent(0x534e4554, "112550251",
+ android.os.Binder.getCallingUid(), "");
+ // Purposefully leaving this method not implemented.
+ throw new RuntimeException("Not implemented");
}
};
@@ -120,10 +126,6 @@
mStorage.write(bytes, 0, bytes.length);
}
- private StatsLogEventWrapper(Parcel in) {
- readFromParcel(in);
- }
-
/**
* Writes the stored fields to a byte array. Will first write a new-line character to denote
* END_LIST before writing contents to byte array.
@@ -134,13 +136,6 @@
}
/**
- * Not implemented.
- */
- public void readFromParcel(Parcel in) {
- // Not needed since this java class is for sending to statsd only.
- }
-
- /**
* Boilerplate for Parcel.
*/
public int describeContents() {
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index d163909..8ed2605 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -80,7 +80,7 @@
* <li>On a small screen it may display only the headers as a single list when first launched.
* Selecting one of the header items will only show the PreferenceFragment of that header (on
* Android N and lower a new Activity is launched).
- * <li>On a large screen in may display both the headers and current PreferenceFragment together as
+ * <li>On a large screen it may display both the headers and current PreferenceFragment together as
* panes. Selecting a header item switches to showing the correct PreferenceFragment for that item.
* </ul>
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6f6a9be..1817972 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10618,6 +10618,15 @@
public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
/**
+ * Feature flag to enable or disable the activity starts logging feature.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String ACTIVITY_STARTS_LOGGING_ENABLED
+ = "activity_starts_logging_enabled";
+
+ /**
* App ops specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 5211767..f8408be 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -33,8 +33,13 @@
import java.util.regex.Pattern;
/**
- * A dataset object represents a group of fields (key / value pairs) used to autofill parts of a
- * screen.
+ * <p>A <code>Dataset</code> object represents a group of fields (key / value pairs) used
+ * to autofill parts of a screen.
+ *
+ * <p>For more information about the role of datasets in the autofill workflow, read
+ * <a href="/guide/topics/text/autofill-services">Build autofill services</a> and the
+ * <code><a href="/reference/android/service/autofill/AutofillService">AutofillService</a></code>
+ * documentation.
*
* <a name="BasicUsage"></a>
* <h3>Basic usage</h3>
@@ -88,10 +93,6 @@
* <li>All other datasets are hidden.
* </ol>
*
- * <a name="MoreInfo"></a>
- * <h3>More information</h3>
- * <p>See {@link android.service.autofill.AutofillService} for more information and examples about
- * the role of datasets in the autofill workflow.
*/
public final class Dataset implements Parcelable {
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 0257891..1695c13 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -21,8 +21,11 @@
import android.os.RemoteException;
/**
- * Handles autofill requests from the {@link AutofillService} into the {@link Activity} being
- * autofilled.
+ * <p><code>FillCallback</code> handles autofill requests from the {@link AutofillService} into
+ * the {@link Activity} being autofilled.
+ *
+ * <p>To learn about using Autofill services in your app, read
+ * <a href="/guide/topics/text/autofill-services">Build autofill services</a>.
*/
public final class FillCallback {
private final IFillCallback mCallback;
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index b6c6bdc..5a7a83f 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -151,14 +151,14 @@
@Override
public String toString() {
return new StringBuilder(Condition.class.getSimpleName()).append('[')
- .append("id=").append(id)
- .append(",summary=").append(summary)
- .append(",line1=").append(line1)
- .append(",line2=").append(line2)
- .append(",icon=").append(icon)
- .append(",state=").append(stateToString(state))
- .append(",flags=").append(flags)
- .append(']').toString();
+ .append("state=").append(stateToString(state))
+ .append(",id=").append(id)
+ .append(",summary=").append(summary)
+ .append(",line1=").append(line1)
+ .append(",line2=").append(line2)
+ .append(",icon=").append(icon)
+ .append(",flags=").append(flags)
+ .append(']').toString();
}
/** @hide */
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index f6749ee..1af2e73 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -244,11 +244,29 @@
.append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
.append(",suppressedVisualEffects=").append(suppressedVisualEffects)
.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd)
- .append(",automaticRules=").append(automaticRules)
- .append(",manualRule=").append(manualRule)
+ .append(",\nautomaticRules=").append(rulesToString())
+ .append(",\nmanualRule=").append(manualRule)
.append(']').toString();
}
+ private String rulesToString() {
+ if (automaticRules.isEmpty()) {
+ return "{}";
+ }
+
+ StringBuilder buffer = new StringBuilder(automaticRules.size() * 28);
+ buffer.append('{');
+ for (int i = 0; i < automaticRules.size(); i++) {
+ if (i > 0) {
+ buffer.append(",\n");
+ }
+ Object value = automaticRules.valueAt(i);
+ buffer.append(value);
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
private Diff diff(ZenModeConfig to) {
final Diff d = new Diff();
if (to == null) {
@@ -1014,10 +1032,10 @@
@UnsupportedAppUsage
public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
final boolean isSchedule = conditionId != null
- && conditionId.getScheme().equals(Condition.SCHEME)
- && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+ && Condition.SCHEME.equals(conditionId.getScheme())
+ && ZenModeConfig.SYSTEM_AUTHORITY.equals(conditionId.getAuthority())
&& conditionId.getPathSegments().size() == 1
- && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH);
+ && ZenModeConfig.SCHEDULE_PATH.equals(conditionId.getPathSegments().get(0));
if (!isSchedule) return null;
final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
@@ -1120,10 +1138,10 @@
public static EventInfo tryParseEventConditionId(Uri conditionId) {
final boolean isEvent = conditionId != null
- && conditionId.getScheme().equals(Condition.SCHEME)
- && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+ && Condition.SCHEME.equals(conditionId.getScheme())
+ && ZenModeConfig.SYSTEM_AUTHORITY.equals(conditionId.getAuthority())
&& conditionId.getPathSegments().size() == 1
- && conditionId.getPathSegments().get(0).equals(EVENT_PATH);
+ && EVENT_PATH.equals(conditionId.getPathSegments().get(0));
if (!isEvent) return null;
final EventInfo rt = new EventInfo();
rt.userId = tryParseInt(conditionId.getQueryParameter("userId"), UserHandle.USER_NULL);
@@ -1338,14 +1356,14 @@
@Override
public String toString() {
return new StringBuilder(ZenRule.class.getSimpleName()).append('[')
- .append("enabled=").append(enabled)
+ .append("id=").append(id)
+ .append(",enabled=").append(String.valueOf(enabled).toUpperCase())
.append(",snoozing=").append(snoozing)
.append(",name=").append(name)
.append(",zenMode=").append(Global.zenModeToString(zenMode))
.append(",conditionId=").append(conditionId)
.append(",condition=").append(condition)
.append(",component=").append(component)
- .append(",id=").append(id)
.append(",creationTime=").append(creationTime)
.append(",enabler=").append(enabler)
.append(']').toString();
@@ -1477,7 +1495,7 @@
final int N = lines.size();
for (int i = 0; i < N; i++) {
if (i > 0) {
- sb.append(',');
+ sb.append(",\n");
}
sb.append(lines.get(i));
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 3afa325..8a49c28 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1590,7 +1590,8 @@
}
float get(final int offset) {
- if (mHorizontals == null) {
+ if (mHorizontals == null || offset < mLineStartOffset
+ || offset >= mLineStartOffset + mHorizontals.length) {
return getHorizontal(offset, mPrimary);
} else {
return mHorizontals[offset - mLineStartOffset];
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index dc07494..aa5ca35 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -23,32 +23,34 @@
import libcore.util.EmptyArray;
/**
- * SparseArrays map integers to Objects. Unlike a normal array of Objects,
- * there can be gaps in the indices. It is intended to be more memory efficient
- * than using a HashMap to map Integers to Objects, both because it avoids
+ * <code>SparseArray</code> maps integers to Objects and, unlike a normal array of Objects,
+ * its indices can contain gaps. <code>SparseArray</code> is intended to be more memory-efficient
+ * than a
+ * <a href="/reference/java/util/HashMap"><code>HashMap</code></a>, because it avoids
* auto-boxing keys and its data structure doesn't rely on an extra entry object
* for each mapping.
*
* <p>Note that this container keeps its mappings in an array data structure,
- * using a binary search to find keys. The implementation is not intended to be appropriate for
+ * using a binary search to find keys. The implementation is not intended to be appropriate for
* data structures
- * that may contain large numbers of items. It is generally slower than a traditional
- * HashMap, since lookups require a binary search and adds and removes require inserting
- * and deleting entries in the array. For containers holding up to hundreds of items,
- * the performance difference is not significant, less than 50%.</p>
+ * that may contain large numbers of items. It is generally slower than a
+ * <code>HashMap</code> because lookups require a binary search,
+ * and adds and removes require inserting
+ * and deleting entries in the array. For containers holding up to hundreds of items,
+ * the performance difference is less than 50%.
*
* <p>To help with performance, the container includes an optimization when removing
* keys: instead of compacting its array immediately, it leaves the removed entry marked
- * as deleted. The entry can then be re-used for the same key, or compacted later in
- * a single garbage collection step of all removed entries. This garbage collection will
- * need to be performed at any time the array needs to be grown or the the map size or
- * entry values are retrieved.</p>
+ * as deleted. The entry can then be re-used for the same key or compacted later in
+ * a single garbage collection of all removed entries. This garbage collection
+ * must be performed whenever the array needs to be grown, or when the map size or
+ * entry values are retrieved.
*
* <p>It is possible to iterate over the items in this container using
* {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
- * <code>keyAt(int)</code> with ascending values of the index will return the
- * keys in ascending order, or the values corresponding to the keys in ascending
- * order in the case of <code>valueAt(int)</code>.</p>
+ * <code>keyAt(int)</code> with ascending values of the index returns the
+ * keys in ascending order. In the case of <code>valueAt(int)</code>, the
+ * values corresponding to the keys are returned in ascending order.
*/
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
@@ -337,7 +339,7 @@
/**
* Returns an index for which {@link #valueAt} would return the
- * specified key, or a negative number if no keys map to the
+ * specified value, or a negative number if no keys map to the
* specified value.
* <p>Beware that this is a linear search, unlike lookups by key,
* and that multiple keys can map to the same value and this will
@@ -361,7 +363,7 @@
/**
* Returns an index for which {@link #valueAt} would return the
- * specified key, or a negative number if no keys map to the
+ * specified value, or a negative number if no keys map to the
* specified value.
* <p>Beware that this is a linear search, unlike lookups by key,
* and that multiple keys can map to the same value and this will
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 496bc9f..5f80d31 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -325,6 +325,7 @@
*
* @hide
*/
+ @VisibleForTesting
public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) {
Region r = Region.obtain();
r.set(left, top, right, bottom);
@@ -422,8 +423,11 @@
m.postTranslate(offsetX, 0);
p.transform(m);
- addToRegion(p, r);
+ final Rect tmpRect = new Rect();
+ toRectAndAddToRegion(p, r, tmpRect);
+ final int topInset = tmpRect.bottom;
+ final int bottomInset;
if (bottomSpec != null) {
final Path bottomPath;
try {
@@ -436,10 +440,17 @@
m.postTranslate(0, displayHeight);
bottomPath.transform(m);
p.addPath(bottomPath);
- addToRegion(bottomPath, r);
+ toRectAndAddToRegion(bottomPath, r, tmpRect);
+ bottomInset = displayHeight - tmpRect.top;
+ } else {
+ bottomInset = 0;
}
- final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r));
+ // Reuse tmpRect as the inset rect we store into the DisplayCutout instance.
+ tmpRect.set(0, topInset, 0, bottomInset);
+ final DisplayCutout cutout = new DisplayCutout(tmpRect, r, false /* copyArguments */);
+
+ final Pair<Path, DisplayCutout> result = new Pair<>(p, cutout);
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
sCachedDisplayWidth = displayWidth;
@@ -450,12 +461,11 @@
return result;
}
- private static void addToRegion(Path p, Region r) {
+ private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
final RectF rectF = new RectF();
- final Rect rect = new Rect();
p.computeBounds(rectF, false /* unused */);
- rectF.round(rect);
- r.op(rect, Op.UNION);
+ rectF.round(inoutRect);
+ inoutRegion.op(inoutRect, Op.UNION);
}
private static Region boundingRectsToRegion(List<Rect> rects) {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 3f7ab2a..38dcdd3 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -33,9 +33,14 @@
import java.util.List;
/**
- * Container for storing additional per-view data generated by {@link View#onProvideStructure
+ * <p><code>ViewStructure</code> is a container for storing additional
+ * per-view data generated by {@link View#onProvideStructure
* View.onProvideStructure} and {@link View#onProvideAutofillStructure
* View.onProvideAutofillStructure}.
+ *
+ * <p>To learn more about using Autofill in your app, read the
+ * <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
+ *
*/
public abstract class ViewStructure {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8b9b856..84a4601 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1699,6 +1699,15 @@
public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
/**
+ * Flag to indicate that the status bar window is now in an explicit expanded state, meaning
+ * that status bar will not be hidden by any window with flag {@link #FLAG_FULLSCREEN} or
+ * {@link View#SYSTEM_UI_FLAG_FULLSCREEN} set.
+ * This can only be set by {@link LayoutParams#TYPE_STATUS_BAR}.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_STATUS_BAR_EXPANDED = 0x00800000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1786,7 +1795,11 @@
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
- name = "IS_SCREEN_DECOR")
+ name = "IS_SCREEN_DECOR"),
+ @ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_STATUS_BAR_EXPANDED,
+ equals = PRIVATE_FLAG_STATUS_BAR_EXPANDED,
+ name = "STATUS_BAR_EXPANDED")
})
@TestApi
public int privateFlags;
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 769ea3e..b382a18 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -628,7 +628,7 @@
}
/**
- * Sets the text before a change.
+ * Gets the text before a change.
*
* @return The text before the change.
*/
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 7555fff..d21cb3e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -77,11 +77,16 @@
import sun.misc.Cleaner;
/**
- * The {@link AutofillManager} provides ways for apps and custom views to integrate with the
- * Autofill Framework lifecycle.
+ * <p>The {@link AutofillManager} class provides ways for apps and custom views to
+ * integrate with the Autofill Framework lifecycle.
+ *
+ * <p>To learn about using Autofill in your app, read
+ * the <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
+ *
+ * <h3 id="autofill-lifecycle">Autofill lifecycle</h3>
*
* <p>The autofill lifecycle starts with the creation of an autofill context associated with an
- * activity context; the autofill context is created when one of the following methods is called for
+ * activity context. The autofill context is created when one of the following methods is called for
* the first time in an activity context, and the current user has an enabled autofill service:
*
* <ul>
@@ -90,7 +95,7 @@
* <li>{@link #requestAutofill(View)}
* </ul>
*
- * <p>Tipically, the context is automatically created when the first view of the activity is
+ * <p>Typically, the context is automatically created when the first view of the activity is
* focused because {@code View.onFocusChanged()} indirectly calls
* {@link #notifyViewEntered(View)}. App developers can call {@link #requestAutofill(View)} to
* explicitly create it (for example, a custom view developer could offer a contextual menu action
@@ -134,7 +139,9 @@
* shows an autofill save UI if the value of savable views have changed. If the user selects the
* option to Save, the current value of the views is then sent to the autofill service.
*
- * <p>It is safe to call into its methods from any thread.
+ * <h3 id="additional-notes">Additional notes</h3>
+ *
+ * <p>It is safe to call <code>AutofillManager</code> methods from any thread.
*/
@SystemService(Context.AUTOFILL_MANAGER_SERVICE)
@RequiresFeature(PackageManager.FEATURE_AUTOFILL)
@@ -2138,7 +2145,11 @@
pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
pw.print(pfx); pw.print("context: "); pw.println(mContext);
- pw.print(pfx); pw.print("client: "); pw.println(getClient());
+ final AutofillClient client = getClient();
+ if (client != null) {
+ pw.print(pfx); pw.print("client: "); pw.print(client);
+ pw.print(" ("); pw.print(client.autofillClientGetActivityToken()); pw.println(')');
+ }
pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -2157,8 +2168,24 @@
pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
- pw.print(pfx); pw.print("compat mode enabled: "); pw.println(
- isCompatibilityModeEnabledLocked());
+ pw.print(pfx); pw.print("compat mode enabled: ");
+ synchronized (mLock) {
+ if (mCompatibilityBridge != null) {
+ final String pfx2 = pfx + " ";
+ pw.println("true");
+ pw.print(pfx2); pw.print("windowId: ");
+ pw.println(mCompatibilityBridge.mFocusedWindowId);
+ pw.print(pfx2); pw.print("nodeId: ");
+ pw.println(mCompatibilityBridge.mFocusedNodeId);
+ pw.print(pfx2); pw.print("virtualId: ");
+ pw.println(AccessibilityNodeInfo
+ .getVirtualDescendantId(mCompatibilityBridge.mFocusedNodeId));
+ pw.print(pfx2); pw.print("focusedBounds: ");
+ pw.println(mCompatibilityBridge.mFocusedBounds);
+ } else {
+ pw.println("false");
+ }
+ }
pw.print(pfx); pw.print("debug: "); pw.print(sDebug);
pw.print(" verbose: "); pw.println(sVerbose);
}
@@ -2292,7 +2319,15 @@
@Override
public AccessibilityEvent onAccessibilityEvent(AccessibilityEvent event,
boolean accessibilityEnabled, int relevantEventTypes) {
- switch (event.getEventType()) {
+ final int type = event.getEventType();
+ if (sVerbose) {
+ // NOTE: this is waaay spammy, but that's life.
+ Log.v(TAG, "onAccessibilityEvent(" + AccessibilityEvent.eventTypeToString(type)
+ + "): virtualId="
+ + AccessibilityNodeInfo.getVirtualDescendantId(event.getSourceNodeId())
+ + ", client=" + getClient());
+ }
+ switch (type) {
case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
synchronized (mLock) {
if (mFocusedWindowId == event.getWindowId()
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index 0c34e3c..4d3bbe4 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -57,7 +57,8 @@
/**
* Clone the entire object to be used in the UI thread by clients of
* WebView. This creates a copy that should never be modified by any of the
- * webkit package classes.
+ * webkit package classes. On Android 4.4 and later there is no need to use
+ * this, as the object is already a read-only copy of the internal state.
*/
protected abstract WebBackForwardList clone();
}
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index 74db039..b9e7042 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -23,7 +23,7 @@
/**
* A convenience class for accessing fields in an entry in the back/forward list
* of a WebView. Each WebHistoryItem is a snapshot of the requested history
- * item. Each history item may be updated during the load of a page.
+ * item.
* @see WebBackForwardList
*/
public abstract class WebHistoryItem implements Cloneable {
@@ -44,8 +44,6 @@
* history item. See getTargetUrl() for the url that is the actual target of
* this history item.
* @return The base url of this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
*/
public abstract String getUrl();
@@ -60,22 +58,20 @@
/**
* Return the document title of this history item.
* @return The document title of this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
*/
public abstract String getTitle();
/**
* Return the favicon of this history item or {@code null} if no favicon was found.
* @return A Bitmap containing the favicon for this history item or {@code null}.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
*/
@Nullable
public abstract Bitmap getFavicon();
/**
- * Clone the history item for use by clients of WebView.
+ * Clone the history item for use by clients of WebView. On Android 4.4 and later
+ * there is no need to use this, as the object is already a read-only copy of the
+ * internal state.
*/
protected abstract WebHistoryItem clone();
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 66e079e..c30edd3 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -991,7 +991,9 @@
* {@link PluginState#OFF}.
*
* @param state a PluginState value
- * @deprecated Plugins will not be supported in future, and should not be used.
+ * @deprecated Plugins are not supported in API level
+ * {@link android.os.Build.VERSION_CODES#KITKAT} or later;
+ * enabling plugins is a no-op.
*/
@Deprecated
public abstract void setPluginState(PluginState state);
@@ -1187,7 +1189,9 @@
*
* @return the plugin state as a {@link PluginState} value
* @see #setPluginState
- * @deprecated Plugins will not be supported in future, and should not be used.
+ * @deprecated Plugins are not supported in API level
+ * {@link android.os.Build.VERSION_CODES#KITKAT} or later;
+ * enabling plugins is a no-op.
*/
@Deprecated
public abstract PluginState getPluginState();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5c5e9de..8f03b69 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -42,7 +42,6 @@
import android.os.RemoteException;
import android.os.StrictMode;
import android.print.PrintDocumentAdapter;
-import android.security.KeyChain;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -1432,9 +1431,8 @@
/**
* Clears the client certificate preferences stored in response
* to proceeding/cancelling client cert requests. Note that WebView
- * automatically clears these preferences when it receives a
- * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are
- * shared by all the WebViews that are created by the embedder application.
+ * automatically clears these preferences when the system keychain is updated.
+ * The preferences are shared by all the WebViews that are created by the embedder application.
*
* @param onCleared A runnable to be invoked when client certs are cleared.
* The runnable will be called in UI thread.
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index f686b66..bdd7a09 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -31,18 +31,25 @@
public class WebViewClient {
/**
- * Give the host application a chance to take over the control when a new
- * url is about to be loaded in the current WebView. If WebViewClient is not
- * provided, by default WebView will ask Activity Manager to choose the
- * proper handler for the url. If WebViewClient is provided, return {@code true}
- * means the host application handles the url, while return {@code false} means the
- * current WebView handles the url.
- * This method is not called for requests using the POST "method".
+ * Give the host application a chance to take control when a URL is about to be loaded in the
+ * current WebView. If a WebViewClient is not provided, by default WebView will ask Activity
+ * Manager to choose the proper handler for the URL. If a WebViewClient is provided, returning
+ * {@code true} causes the current WebView to abort loading the URL, while returning
+ * {@code false} causes the WebView to continue loading the URL as usual.
+ *
+ * <p class="note"><b>Note:</b> Do not call {@link WebView#loadUrl(String)} with the same
+ * URL and then return {@code true}. This unnecessarily cancels the current load and starts a
+ * new load with the same URL. The correct way to continue loading a given URL is to simply
+ * return {@code false}, without calling {@link WebView#loadUrl(String)}.
+ *
+ * <p class="note"><b>Note:</b> This method is not called for POST requests.
+ *
+ * <p class="note"><b>Note:</b> This method may be called for subframes and with non-HTTP(S)
+ * schemes; calling {@link WebView#loadUrl(String)} with such a URL will fail.
*
* @param view The WebView that is initiating the callback.
- * @param url The url to be loaded.
- * @return {@code true} if the host application wants to leave the current WebView
- * and handle the url itself, otherwise return {@code false}.
+ * @param url The URL to be loaded.
+ * @return {@code true} to cancel the current load, otherwise return {@code false}.
* @deprecated Use {@link #shouldOverrideUrlLoading(WebView, WebResourceRequest)
* shouldOverrideUrlLoading(WebView, WebResourceRequest)} instead.
*/
@@ -52,26 +59,25 @@
}
/**
- * Give the host application a chance to take over the control when a new
- * url is about to be loaded in the current WebView. If WebViewClient is not
- * provided, by default WebView will ask Activity Manager to choose the
- * proper handler for the url. If WebViewClient is provided, return {@code true}
- * means the host application handles the url, while return {@code false} means the
- * current WebView handles the url.
+ * Give the host application a chance to take control when a URL is about to be loaded in the
+ * current WebView. If a WebViewClient is not provided, by default WebView will ask Activity
+ * Manager to choose the proper handler for the URL. If a WebViewClient is provided, returning
+ * {@code true} causes the current WebView to abort loading the URL, while returning
+ * {@code false} causes the WebView to continue loading the URL as usual.
*
- * <p>Notes:
- * <ul>
- * <li>This method is not called for requests using the POST "method".</li>
- * <li>This method is also called for subframes with non-http schemes, thus it is
- * strongly disadvised to unconditionally call {@link WebView#loadUrl(String)}
- * with the request's url from inside the method and then return {@code true},
- * as this will make WebView to attempt loading a non-http url, and thus fail.</li>
- * </ul>
+ * <p class="note"><b>Note:</b> Do not call {@link WebView#loadUrl(String)} with the request's
+ * URL and then return {@code true}. This unnecessarily cancels the current load and starts a
+ * new load with the same URL. The correct way to continue loading a given URL is to simply
+ * return {@code false}, without calling {@link WebView#loadUrl(String)}.
+ *
+ * <p class="note"><b>Note:</b> This method is not called for POST requests.
+ *
+ * <p class="note"><b>Note:</b> This method may be called for subframes and with non-HTTP(S)
+ * schemes; calling {@link WebView#loadUrl(String)} with such a URL will fail.
*
* @param view The WebView that is initiating the callback.
* @param request Object containing the details of the request.
- * @return {@code true} if the host application wants to leave the current WebView
- * and handle the url itself, otherwise return {@code false}.
+ * @return {@code true} to cancel the current load, otherwise return {@code false}.
*/
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl().toString());
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 3956215..66ce0ee 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -812,7 +812,7 @@
* @param firstVisibleItem the index of the first visible cell (ignore if
* visibleItemCount == 0)
* @param visibleItemCount the number of visible cells
- * @param totalItemCount the number of items in the list adaptor
+ * @param totalItemCount the number of items in the list adapter
*/
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount);
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 398d087..4728124 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -16,14 +16,21 @@
package com.android.internal.app;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.RemoteException;
@@ -31,12 +38,11 @@
import android.os.UserManager;
import android.util.Slog;
import android.widget.Toast;
-
import com.android.internal.annotations.VisibleForTesting;
-
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
-
-import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import java.util.Set;
/**
* This is used in conjunction with
@@ -44,7 +50,6 @@
* be passed in and out of a managed profile.
*/
public class IntentForwarderActivity extends Activity {
-
public static String TAG = "IntentForwarderActivity";
public static String FORWARD_INTENT_TO_PARENT
@@ -53,6 +58,9 @@
public static String FORWARD_INTENT_TO_MANAGED_PROFILE
= "com.android.internal.app.ForwardIntentToManagedProfile";
+ private static final Set<String> ALLOWED_TEXT_MESSAGE_SCHEME
+ = new HashSet<>(Arrays.asList("sms", "smsto", "mms", "mmsto"));
+
private Injector mInjector;
@Override
@@ -93,19 +101,8 @@
newIntent.prepareToLeaveUser(callingUserId);
}
- final android.content.pm.ResolveInfo ri =
- mInjector.getPackageManager().resolveActivityAsUser(
- newIntent,
- MATCH_DEFAULT_ONLY,
- targetUserId);
-
- // Don't show the disclosure if next activity is ResolverActivity or ChooserActivity
- // as those will already have shown work / personal as neccesary etc.
- final boolean shouldShowDisclosure = ri == null || ri.activityInfo == null ||
- !"android".equals(ri.activityInfo.packageName) ||
- !(ResolverActivity.class.getName().equals(ri.activityInfo.name)
- || ChooserActivity.class.getName().equals(ri.activityInfo.name));
-
+ final ResolveInfo ri = mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY,
+ targetUserId);
try {
startActivityAsCaller(newIntent, null, false, targetUserId);
} catch (RuntimeException e) {
@@ -124,8 +121,8 @@
+ ActivityThread.currentProcessName(), e);
}
- if (shouldShowDisclosure) {
- Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
+ if (shouldShowDisclosure(ri, intentReceived)) {
+ mInjector.showToast(userMessageId, Toast.LENGTH_LONG);
}
} else {
Slog.wtf(TAG, "the intent: " + intentReceived + " cannot be forwarded from user "
@@ -134,6 +131,35 @@
finish();
}
+ private boolean shouldShowDisclosure(@Nullable ResolveInfo ri, Intent intent) {
+ if (ri == null || ri.activityInfo == null) {
+ return true;
+ }
+ if (ri.activityInfo.applicationInfo.isSystemApp()
+ && (isDialerIntent(intent) || isTextMessageIntent(intent))) {
+ return false;
+ }
+ return !isTargetResolverOrChooserActivity(ri.activityInfo);
+ }
+
+ private boolean isTextMessageIntent(Intent intent) {
+ return Intent.ACTION_SENDTO.equals(intent.getAction()) && intent.getData() != null
+ && ALLOWED_TEXT_MESSAGE_SCHEME.contains(intent.getData().getScheme());
+ }
+
+ private boolean isDialerIntent(Intent intent) {
+ return Intent.ACTION_DIAL.equals(intent.getAction())
+ || Intent.ACTION_CALL.equals(intent.getAction());
+ }
+
+ private boolean isTargetResolverOrChooserActivity(ActivityInfo activityInfo) {
+ if (!"android".equals(activityInfo.packageName)) {
+ return false;
+ }
+ return ResolverActivity.class.getName().equals(activityInfo.name)
+ || ChooserActivity.class.getName().equals(activityInfo.name);
+ }
+
/**
* Check whether the intent can be forwarded to target user. Return the intent used for
* forwarding if it can be forwarded, {@code null} otherwise.
@@ -241,6 +267,16 @@
public PackageManager getPackageManager() {
return IntentForwarderActivity.this.getPackageManager();
}
+
+ @Override
+ public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
+ return getPackageManager().resolveActivityAsUser(intent, flags, userId);
+ }
+
+ @Override
+ public void showToast(int messageId, int duration) {
+ Toast.makeText(IntentForwarderActivity.this, getString(messageId), duration).show();
+ }
}
public interface Injector {
@@ -249,5 +285,9 @@
UserManager getUserManager();
PackageManager getPackageManager();
+
+ ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+
+ void showToast(@StringRes int messageId, int duration);
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 94c3933..e6dc352 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4031,7 +4031,9 @@
try {
IBatteryPropertiesRegistrar registrar = IBatteryPropertiesRegistrar.Stub.asInterface(
ServiceManager.getService("batteryproperties"));
- registrar.scheduleUpdate();
+ if (registrar != null) {
+ registrar.scheduleUpdate();
+ }
} catch (RemoteException e) {
// Ignore.
}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 64b1f24..0c8613b 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -111,14 +111,16 @@
final int childHeight = child.getMeasuredHeight();
int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
lp.bottomMargin + spacing);
- first = false;
int measureType = MessagingChild.MEASURED_NORMAL;
if (messagingChild != null) {
measureType = messagingChild.getMeasuredType();
linesRemaining -= messagingChild.getConsumedLines();
}
- boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED;
- boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL;
+
+ // We never measure the first item as too small, we want to at least show something.
+ boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL && !first;
+ boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED
+ || measureType == MessagingChild.MEASURED_TOO_SMALL && first;
if (newHeight <= targetHeight && !isTooSmall) {
totalHeight = newHeight;
measuredWidth = Math.max(measuredWidth,
@@ -131,6 +133,7 @@
} else {
break;
}
+ first = false;
}
setMeasuredDimension(
diff --git a/core/res/res/values-mcc214-mnc01/config.xml b/core/res/res/values-mcc214-mnc01/config.xml
index 24150a7..41e24d7 100644
--- a/core/res/res/values-mcc214-mnc01/config.xml
+++ b/core/res/res/values-mcc214-mnc01/config.xml
@@ -40,4 +40,7 @@
<item>INTERNET,airtelnet.es,,,vodafone,vodafone,,,,,214,01,1,DUN</item>
</string-array>
+ <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+ <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc222-mnc10/config.xml b/core/res/res/values-mcc222-mnc10/config.xml
index c819de2..0085a1b 100644
--- a/core/res/res/values-mcc222-mnc10/config.xml
+++ b/core/res/res/values-mcc222-mnc10/config.xml
@@ -28,4 +28,8 @@
<string-array translatable="false" name="config_tether_apndata">
<item>Tethering Internet,web.omnitel.it,,,,,,,,,222,10,,DUN</item>
</string-array>
+
+ <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+ <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc234-mnc15/config.xml b/core/res/res/values-mcc234-mnc15/config.xml
new file mode 100644
index 0000000..84e779d
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc15/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+ <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc234-mnc91/config.xml b/core/res/res/values-mcc234-mnc91/config.xml
new file mode 100644
index 0000000..84e779d
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc91/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+ <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc262-mnc02/config.xml b/core/res/res/values-mcc262-mnc02/config.xml
new file mode 100644
index 0000000..84e779d
--- /dev/null
+++ b/core/res/res/values-mcc262-mnc02/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+ <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 969b602..8f1c932 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -670,6 +670,10 @@
<!-- Boolean indicating whether framework needs to set the tx power limit for meeting SAR requirements -->
<bool translatable="false" name="config_wifi_framework_enable_sar_tx_power_limit">false</bool>
+ <!-- Boolean indicating whether framework should use detection of softAP mode to set the tx
+ power limit for meeting SAR requirements -->
+ <bool translatable="false" name="config_wifi_framework_enable_soft_ap_sar_tx_power_limit">false</bool>
+
<!-- Boolean indicating whether framework needs to use body proximity to set the tx power limit
for meeting SAR requirements -->
<bool translatable="false" name="config_wifi_framework_enable_body_proximity_sar_tx_power_limit">false</bool>
@@ -2357,6 +2361,9 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">true</bool>
+ <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+ <bool name="config_safe_media_disable_on_volume_up">true</bool>
+
<!-- Set to true if the wifi display supports compositing content stored
in gralloc protected buffers. For this to be true, there must exist
a protected hardware path for surface flinger to composite and send
@@ -2979,6 +2986,10 @@
-->
<bool name="config_fillMainBuiltInDisplayCutout">false</bool>
+ <!-- If true, and there is a cutout on the main built in display, the cutout will be masked
+ by shrinking the display such that it does not overlap the cutout area. -->
+ <bool name="config_maskMainBuiltInDisplayCutout">false</bool>
+
<!-- Ultrasound support for Mic/speaker path -->
<!-- Whether the default microphone audio source supports near-ultrasound frequencies
(range of 18 - 21 kHz). -->
@@ -3502,4 +3513,11 @@
<!-- Whether or not we should show the option to show battery percentage -->
<bool name="config_battery_percentage_setting_available">true</bool>
+
+ <!-- Model of potentially misprovisioned devices. If none is specified in an overlay, an
+ empty string is passed in. -->
+ <string name="config_misprovisionedDeviceModel" translatable="false"></string>
+
+ <!-- Brand value for attestation of misprovisioned device. -->
+ <string name="config_misprovisionedBrandValue" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 471170b..73cb59e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -61,6 +61,15 @@
<!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
<dimen name="status_bar_edge_ignore">5dp</dimen>
+ <!-- Default radius of the software rounded corners. -->
+ <dimen name="rounded_corner_radius">0dp</dimen>
+ <!-- Radius of the software rounded corners at the top of the display in its natural
+ orientation. If zero, the value of rounded_corner_radius is used. -->
+ <dimen name="rounded_corner_radius_top">0dp</dimen>
+ <!-- Radius of the software rounded corners at the bottom of the display in its natural
+ orientation. If zero, the value of rounded_corner_radius is used. -->
+ <dimen name="rounded_corner_radius_bottom">0dp</dimen>
+
<!-- Width of the window of the divider bar used to resize docked stacks. -->
<dimen name="docked_stack_divider_thickness">48dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9520d6d..4fd94a2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -310,6 +310,7 @@
<java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
<java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
<java-symbol type="bool" name="config_safe_media_volume_enabled" />
+ <java-symbol type="bool" name="config_safe_media_disable_on_volume_up" />
<java-symbol type="bool" name="config_camera_sound_forced" />
<java-symbol type="bool" name="config_dontPreferApn" />
<java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
@@ -338,6 +339,7 @@
<java-symbol type="bool" name="config_wifi_framework_use_single_radio_chain_scan_results_network_selection" />
<java-symbol type="bool" name="config_wifi_only_link_same_credential_configurations" />
<java-symbol type="bool" name="config_wifi_framework_enable_sar_tx_power_limit" />
+ <java-symbol type="bool" name="config_wifi_framework_enable_soft_ap_sar_tx_power_limit" />
<java-symbol type="bool" name="config_wifi_framework_enable_body_proximity_sar_tx_power_limit" />
<java-symbol type="string" name="config_wifi_sar_sensor_type" />
<java-symbol type="integer" name="config_wifi_framework_sar_free_space_event_id" />
@@ -3407,6 +3409,11 @@
<java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
<java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
+ <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
+
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
+
+ <java-symbol type="string" name="config_misprovisionedDeviceModel" />
+ <java-symbol type="string" name="config_misprovisionedBrandValue" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 4833816..090f9af 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -306,6 +306,7 @@
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.PopupMenu</item>
+ <item name="popupTheme">@null</item>
<item name="activityChooserViewStyle">@style/Widget.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.FragmentBreadCrumbs</item>
<item name="contextPopupMenuStyle">?attr/popupMenuStyle</item>
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index cb5b93d..33832d4 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -296,6 +296,7 @@
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.Holo.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.Holo.PopupMenu</item>
+ <item name="popupTheme">@null</item>
<item name="stackViewStyle">@style/Widget.Holo.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Holo.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.FragmentBreadCrumbs</item>
@@ -658,9 +659,11 @@
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.Holo.Light.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.Holo.Light.PopupMenu</item>
+ <item name="popupTheme">@null</item>
<item name="stackViewStyle">@style/Widget.Holo.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Holo.Light.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.Light.FragmentBreadCrumbs</item>
+ <item name="contextPopupMenuStyle">?attr/popupMenuStyle</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 43af1a3..583b2cd 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -99,6 +99,7 @@
private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS =
newHashSet(
Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
+ Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED,
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
Settings.Global.ADB_ENABLED,
Settings.Global.ADD_USERS_WHEN_LOCKED,
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index 6ee74cb..fe45fe7 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -19,6 +19,7 @@
import static android.view.DisplayCutout.NO_CUTOUT;
import static android.view.DisplayCutout.fromSpec;
+import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
@@ -220,6 +221,19 @@
}
@Test
+ public void fromSpec_setsSafeInsets_top() {
+ DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z", 200, 400, 2f);
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 0)));
+ }
+
+ @Test
+ public void fromSpec_setsSafeInsets_top_and_bottom() {
+ DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z"
+ + "@bottom M -50,0 v -10,0 h 100 v 20 z", 200, 400, 2f);
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 10)));
+ }
+
+ @Test
public void parcel_unparcel_nocutout() {
Parcel p = Parcel.obtain();
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index b18fa74..c165b6b 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -16,33 +16,6 @@
package com.android.internal.app;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -51,11 +24,42 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
@RunWith(AndroidJUnit4.class)
public class IntentForwarderActivityTest {
+
private static final ComponentName FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME =
new ComponentName(
"android",
@@ -77,22 +81,26 @@
private static IntentForwarderActivity.Injector sInjector;
private static ComponentName sComponentName;
+ private static String sActivityName;
+ private static String sPackageName;
@Mock private IPackageManager mIPm;
@Mock private PackageManager mPm;
@Mock private UserManager mUserManager;
+ @Mock private ApplicationInfo mApplicationInfo;
@Rule
public ActivityTestRule<IntentForwarderWrapperActivity> mActivityRule =
new ActivityTestRule<>(IntentForwarderWrapperActivity.class, true, false);
private Context mContext;
+ public static final String PHONE_NUMBER = "123-456-789";
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getTargetContext();
- sInjector = new TestInjector();
+ sInjector = spy(new TestInjector());
}
@Test
@@ -252,6 +260,149 @@
assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
}
+ @Test
+ public void shouldSkipDisclosure_notWhitelisted() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SEND)
+ .setType(TYPE_PLAIN_TEXT);
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_withResolverActivity() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ sActivityName = ResolverActivity.class.getName();
+ sPackageName = "android";
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SEND)
+ .setType(TYPE_PLAIN_TEXT);
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_callIntent_call() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_CALL);
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_callIntent_dial() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_DIAL);
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_callIntent_notCallOrDial() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_ALARM_CHANGED);
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_textMessageIntent_sms() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SENDTO)
+ .setData(Uri.fromParts("sms", PHONE_NUMBER, null));
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_textMessageIntent_smsto() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SENDTO)
+ .setData(Uri.fromParts("smsto", PHONE_NUMBER, null));
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_textMessageIntent_mms() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SENDTO)
+ .setData(Uri.fromParts("mms", PHONE_NUMBER, null));
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_textMessageIntent_mmsto() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SENDTO)
+ .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null));
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
+ public void shouldSkipDisclosure_textMessageIntent_invalidUri() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_SENDTO)
+ .setData(Uri.fromParts("invalid", PHONE_NUMBER, null));
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector).showToast(anyInt(), anyInt());
+ }
+
+ private void setupShouldSkipDisclosureTest() throws RemoteException {
+ sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
+ sActivityName = "MyTestActivity";
+ sPackageName = "test.package.name";
+ when(mApplicationInfo.isSystemApp()).thenReturn(true);
+ // Managed profile exists.
+ List<UserInfo> profiles = new ArrayList<>();
+ profiles.add(CURRENT_USER_INFO);
+ profiles.add(MANAGED_PROFILE_INFO);
+ when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
+ // Intent can be forwarded.
+ when(mIPm.canForwardTo(
+ any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
+ }
public static class IntentForwarderWrapperActivity extends IntentForwarderActivity {
private Intent mStartActivityIntent;
@@ -276,7 +427,7 @@
}
}
- class TestInjector implements IntentForwarderActivity.Injector {
+ public class TestInjector implements IntentForwarderActivity.Injector {
@Override
public IPackageManager getIPackageManager() {
@@ -292,5 +443,21 @@
public PackageManager getPackageManager() {
return mPm;
}
+
+ @Override
+ public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = sPackageName;
+ activityInfo.name = sActivityName;
+ activityInfo.applicationInfo = mApplicationInfo;
+
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = activityInfo;
+
+ return resolveInfo;
+ }
+
+ @Override
+ public void showToast(int messageId, int duration) {}
}
}
\ No newline at end of file
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 2503381..ef58c8f 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1600,9 +1600,9 @@
* Draw the specified circle using the specified paint. If radius is <= 0, then nothing will be
* drawn. The circle will be filled or framed based on the Style in the paint.
*
- * @param cx The x-coordinate of the center of the cirle to be drawn
- * @param cy The y-coordinate of the center of the cirle to be drawn
- * @param radius The radius of the cirle to be drawn
+ * @param cx The x-coordinate of the center of the circle to be drawn
+ * @param cy The y-coordinate of the center of the circle to be drawn
+ * @param radius The radius of the circle to be drawn
* @param paint The paint used to draw the circle
*/
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 419eb24..953cef7d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -301,6 +301,9 @@
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, (mKeySizeBits + 7) / 8);
int flags = 0;
+ if (spec.isStrongBoxBacked()) {
+ flags |= KeyStore.FLAG_STRONGBOX;
+ }
String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + spec.getKeystoreAlias();
KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
boolean success = false;
@@ -314,8 +317,12 @@
flags,
resultingKeyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(
- "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
+ if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
+ throw new StrongBoxUnavailableException("Failed to generate key");
+ } else {
+ throw new ProviderException(
+ "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
+ }
}
@KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
try {
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 1be8309..f7993ef 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -22,9 +22,9 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
+import android.content.res.Resources;
import android.os.Build;
import android.security.KeyStore;
-import android.security.KeyStoreException;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
@@ -117,6 +117,40 @@
@NonNull public static KeymasterArguments prepareAttestationArguments(Context context,
@NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
DeviceIdAttestationException {
+ return prepareAttestationArguments(context, idTypes,attestationChallenge, Build.BRAND);
+ }
+
+ /**
+ * Prepares Keymaster Arguments with attestation data for misprovisioned Pixel 2 device.
+ * See http://go/keyAttestationFailure and http://b/69471841 for more info.
+ * @hide should only be used by KeyChain.
+ */
+ @NonNull public static KeymasterArguments prepareAttestationArgumentsIfMisprovisioned(
+ Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ DeviceIdAttestationException {
+ if (!isPotentiallyMisprovisionedDevice(context)) {
+ return null;
+ }
+ Resources resources = context.getResources();
+ String misprovisionedBrand = resources.getString(
+ com.android.internal.R.string.config_misprovisionedBrandValue);
+ return prepareAttestationArguments(
+ context, idTypes, attestationChallenge, misprovisionedBrand);
+ }
+
+ @NonNull private static boolean isPotentiallyMisprovisionedDevice(Context context) {
+ Resources resources = context.getResources();
+ String misprovisionedModel = resources.getString(
+ com.android.internal.R.string.config_misprovisionedDeviceModel);
+ String misprovisionedBrand = resources.getString(
+ com.android.internal.R.string.config_misprovisionedBrandValue);
+
+ return (Build.MODEL.equals(misprovisionedModel));
+ }
+
+ @NonNull private static KeymasterArguments prepareAttestationArguments(Context context,
+ @NonNull int[] idTypes, @NonNull byte[] attestationChallenge, String brand) throws
+ DeviceIdAttestationException {
// Check method arguments, retrieve requested device IDs and prepare attestation arguments.
if (attestationChallenge == null) {
throw new NullPointerException("Missing attestation challenge");
@@ -169,7 +203,7 @@
}
}
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
- Build.BRAND.getBytes(StandardCharsets.UTF_8));
+ brand.getBytes(StandardCharsets.UTF_8));
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
Build.DEVICE.getBytes(StandardCharsets.UTF_8));
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 3643ca4..8a02a82 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -18,6 +18,7 @@
import android.os.SystemClock;
import android.os.connectivity.GpsBatteryStats;
+import android.os.SystemProperties;
import android.text.format.DateUtils;
import android.util.Base64;
@@ -175,6 +176,7 @@
= topFourAverageCn0Statistics.getStandardDeviation();
}
msg.powerMetrics = mGnssPowerMetrics.buildProto();
+ msg.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
reset();
return s;
@@ -239,6 +241,7 @@
s.append(" Energy consumed while on battery (mAh): ").append(
stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS)).append("\n");
}
+ s.append("Hardware Version: " + SystemProperties.get("ro.boot.revision", "")).append("\n");
return s.toString();
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 76fc9e3..d45acdf 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -405,7 +405,7 @@
<p>
The codec in turn will return a read-only output buffer via the {@link
Callback#onOutputBufferAvailable onOutputBufferAvailable} callback in asynchronous mode, or in
- response to a {@link #dequeueOutputBuffer dequeuOutputBuffer} call in synchronous mode. After the
+ response to a {@link #dequeueOutputBuffer dequeueOutputBuffer} call in synchronous mode. After the
output buffer has been processed, call one of the {@link #releaseOutputBuffer
releaseOutputBuffer} methods to return the buffer to the codec.
<p>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index a3c1fc6..fd80edf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -62,6 +62,7 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.text.Collator;
import java.text.Normalizer;
import java.text.Normalizer.Form;
@@ -132,7 +133,7 @@
boolean mSessionsChanged;
// Temporary for dispatching session callbacks. Only touched by main thread.
- final ArrayList<Session> mActiveSessions = new ArrayList<Session>();
+ final ArrayList<WeakReference<Session>> mActiveSessions = new ArrayList<>();
final HandlerThread mThread;
final BackgroundHandler mBackgroundHandler;
@@ -618,7 +619,7 @@
for (int i=0; i<mSessions.size(); i++) {
Session s = mSessions.get(i);
if (s.mResumed) {
- mActiveSessions.add(s);
+ mActiveSessions.add(new WeakReference<>(s));
}
}
}
@@ -830,46 +831,70 @@
rebuildActiveSessions();
switch (msg.what) {
case MSG_REBUILD_COMPLETE: {
- Session s = (Session)msg.obj;
- if (mActiveSessions.contains(s)) {
- s.mCallbacks.onRebuildComplete(s.mLastAppList);
+ Session s = (Session) msg.obj;
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null && session == s) {
+ s.mCallbacks.onRebuildComplete(s.mLastAppList);
+ }
}
} break;
case MSG_PACKAGE_LIST_CHANGED: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onPackageListChanged();
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onPackageListChanged();
+ }
}
} break;
case MSG_PACKAGE_ICON_CHANGED: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onPackageIconChanged();
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onPackageIconChanged();
+ }
}
} break;
case MSG_PACKAGE_SIZE_CHANGED: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onPackageSizeChanged(
- (String)msg.obj);
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onPackageSizeChanged(
+ (String) msg.obj);
+ }
}
} break;
case MSG_ALL_SIZES_COMPUTED: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onAllSizesComputed();
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onAllSizesComputed();
+ }
}
} break;
case MSG_RUNNING_STATE_CHANGED: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onRunningStateChanged(
- msg.arg1 != 0);
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onRunningStateChanged(
+ msg.arg1 != 0);
+ }
}
} break;
case MSG_LAUNCHER_INFO_CHANGED: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onLauncherInfoChanged();
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onLauncherInfoChanged();
+ }
}
} break;
case MSG_LOAD_ENTRIES_COMPLETE: {
- for (int i=0; i<mActiveSessions.size(); i++) {
- mActiveSessions.get(i).mCallbacks.onLoadEntriesCompleted();
+ for (WeakReference<Session> sessionRef : mActiveSessions) {
+ final Session session = sessionRef.get();
+ if (session != null) {
+ session.mCallbacks.onLoadEntriesCompleted();
+ }
}
} break;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
index 3732471..1c50953 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
@@ -19,6 +19,8 @@
import android.content.Context;
import android.util.Log;
+import java.lang.ref.WeakReference;
+
/**
* LocalBluetoothManager provides a simplified interface on top of a subset of
* the Bluetooth API. Note that {@link #getInstance} will return null
@@ -34,7 +36,7 @@
private final Context mContext;
/** If a BT-related activity is in the foreground, this will be it. */
- private Context mForegroundActivity;
+ private WeakReference<Context> mForegroundActivity;
private final LocalBluetoothAdapter mLocalAdapter;
@@ -85,17 +87,19 @@
}
public Context getForegroundActivity() {
- return mForegroundActivity;
+ return mForegroundActivity == null
+ ? null
+ : mForegroundActivity.get();
}
public boolean isForegroundActivity() {
- return mForegroundActivity != null;
+ return mForegroundActivity != null && mForegroundActivity.get() != null;
}
public synchronized void setForegroundActivity(Context context) {
if (context != null) {
Log.d(TAG, "setting foreground activity to non-null context");
- mForegroundActivity = context;
+ mForegroundActivity = new WeakReference<>(context);
} else {
if (mForegroundActivity != null) {
Log.d(TAG, "setting foreground activity to null");
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 988060e..e5d97c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -36,12 +36,12 @@
import android.util.Log;
import android.util.Xml;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -97,15 +97,15 @@
}
public DreamBackend(Context context) {
- mContext = context;
+ mContext = context.getApplicationContext();
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
mComparator = new DreamInfoComparator(getDefaultDream());
- mDreamsEnabledByDefault = context.getResources()
+ mDreamsEnabledByDefault = mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault);
- mDreamsActivatedOnSleepByDefault = context.getResources()
+ mDreamsActivatedOnSleepByDefault = mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
- mDreamsActivatedOnDockByDefault = context.getResources()
+ mDreamsActivatedOnDockByDefault = mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 61f7fe8..bf4374a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -43,7 +43,7 @@
boolean isAvailable();
void setTileSpec(String tileSpec);
- void clearState();
+ @Deprecated default void clearState() {}
void refreshState();
void addCallback(Callback callback);
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index be80d52..79e1fae 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -943,9 +943,9 @@
<dimen name="bottom_padding">48dp</dimen>
<dimen name="edge_margin">8dp</dimen>
- <dimen name="rounded_corner_radius">0dp</dimen>
- <dimen name="rounded_corner_radius_top">0dp</dimen>
- <dimen name="rounded_corner_radius_bottom">0dp</dimen>
+ <dimen name="rounded_corner_radius">@*android:dimen/rounded_corner_radius</dimen>
+ <dimen name="rounded_corner_radius_top">@*android:dimen/rounded_corner_radius_top</dimen>
+ <dimen name="rounded_corner_radius_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
<dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9e4810c..009ba48 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -15,7 +15,6 @@
*/
package com.android.keyguard;
-import android.R.style;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
@@ -26,7 +25,6 @@
import android.util.Log;
import android.util.Slog;
import android.util.StatsLog;
-import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
@@ -142,6 +140,7 @@
mSecurityViewFlipper.addView(v);
updateSecurityView(v);
view = (KeyguardSecurityView)v;
+ view.reset();
}
return view;
@@ -209,7 +208,7 @@
if (messageId != 0) {
final String message = mContext.getString(messageId,
- KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(userId),
+ mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
timeoutInSeconds);
showDialog(null, message);
}
@@ -254,8 +253,8 @@
}
private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
- final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- final int failedAttempts = monitor.getFailedUnlockAttempts(userId) + 1; // +1 for this time
+ // +1 for this time
+ final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
@@ -289,7 +288,6 @@
showWipeDialog(failedAttempts, userType);
}
}
- monitor.reportFailedStrongAuthUnlockAttempt(userId);
mLockPatternUtils.reportFailedPasswordAttempt(userId);
if (timeoutMs > 0) {
mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
@@ -433,7 +431,6 @@
if (success) {
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
- monitor.clearFailedUnlockAttempts();
mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
} else {
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ef3aa42..0e21815 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -209,9 +209,6 @@
// Battery status
private BatteryStatus mBatteryStatus;
- // Password attempts
- private SparseIntArray mFailedAttempts = new SparseIntArray();
-
private final StrongAuthTracker mStrongAuthTracker;
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
@@ -1800,22 +1797,10 @@
return mDeviceProvisioned;
}
- public void clearFailedUnlockAttempts() {
- mFailedAttempts.delete(sCurrentUser);
- }
-
public ServiceState getServiceState(int subId) {
return mServiceStates.get(subId);
}
- public int getFailedUnlockAttempts(int userId) {
- return mFailedAttempts.get(userId, 0);
- }
-
- public void reportFailedStrongAuthUnlockAttempt(int userId) {
- mFailedAttempts.put(userId, getFailedUnlockAttempts(userId) + 1);
- }
-
public void clearFingerprintRecognized() {
mUserFingerprintAuthenticated.clear();
mTrustManager.clearAllFingerprints();
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 79302f2..16b54b4 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -39,10 +39,13 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.SystemProperties;
import android.provider.Settings.Secure;
import androidx.annotation.VisibleForTesting;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
@@ -57,6 +60,7 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.internal.util.Preconditions;
import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
@@ -74,6 +78,9 @@
* for antialiasing and emulation purposes.
*/
public class ScreenDecorations extends SystemUI implements Tunable {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "ScreenDecorations";
+
public static final String SIZE = "sysui_rounded_size";
public static final String PADDING = "sysui_rounded_content_padding";
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
@@ -82,9 +89,9 @@
private DisplayManager mDisplayManager;
private DisplayManager.DisplayListener mDisplayListener;
- private int mRoundedDefault;
- private int mRoundedDefaultTop;
- private int mRoundedDefaultBottom;
+ @VisibleForTesting protected int mRoundedDefault;
+ @VisibleForTesting protected int mRoundedDefaultTop;
+ @VisibleForTesting protected int mRoundedDefaultBottom;
private View mOverlay;
private View mBottomOverlay;
private float mDensity;
@@ -93,26 +100,30 @@
private DisplayCutoutView mCutoutTop;
private DisplayCutoutView mCutoutBottom;
private boolean mPendingRotationChange;
+ private Handler mHandler;
@Override
public void start() {
+ mHandler = startHandlerThread();
+ mHandler.post(this::startOnScreenDecorationsThread);
+ setupStatusBarPaddingIfNeeded();
+ }
+
+ @VisibleForTesting
+ Handler startHandlerThread() {
+ HandlerThread thread = new HandlerThread("ScreenDecorations");
+ thread.start();
+ return thread.getThreadHandler();
+ }
+
+ private void startOnScreenDecorationsThread() {
+ mRotation = RotationUtils.getExactRotation(mContext);
mWindowManager = mContext.getSystemService(WindowManager.class);
- mRoundedDefault = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_radius);
- mRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_radius_top);
- mRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_radius_bottom);
+ updateRoundedCornerRadii();
if (hasRoundedCorners() || shouldDrawCutout()) {
setupDecorations();
}
- int padding = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_content_padding);
- if (padding != 0) {
- setupPadding(padding);
- }
-
mDisplayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
@@ -126,8 +137,8 @@
@Override
public void onDisplayChanged(int displayId) {
- if (mOverlay != null && mBottomOverlay != null
- && mRotation != RotationUtils.getExactRotation(mContext)) {
+ final int newRotation = RotationUtils.getExactRotation(mContext);
+ if (mOverlay != null && mBottomOverlay != null && mRotation != newRotation) {
// We cannot immediately update the orientation. Otherwise
// WindowManager is still deferring layout until it has finished dispatching
// the config changes, which may cause divergence between what we draw
@@ -136,20 +147,24 @@
// - we are trying to redraw. This because WM resized our window and told us to.
// - the config change has been dispatched, so WM is no longer deferring layout.
mPendingRotationChange = true;
- mOverlay.getViewTreeObserver().addOnPreDrawListener(
- new RestartingPreDrawListener(mOverlay));
- mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
- new RestartingPreDrawListener(mBottomOverlay));
+ if (DEBUG) {
+ Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at "
+ + mRotation);
+ }
+ mOverlay.getViewTreeObserver().addOnPreDrawListener(
+ new RestartingPreDrawListener(mOverlay, newRotation));
+ mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
+ new RestartingPreDrawListener(mBottomOverlay, newRotation));
}
updateOrientation();
}
};
- mRotation = -1;
mDisplayManager = (DisplayManager) mContext.getSystemService(
Context.DISPLAY_SERVICE);
- mDisplayManager.registerDisplayListener(mDisplayListener, null);
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ updateOrientation();
}
private void setupDecorations() {
@@ -179,10 +194,11 @@
mWindowManager.getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
- Dependency.get(TunerService.class).addTunable(this, SIZE);
+ Dependency.get(Dependency.MAIN_HANDLER).post(
+ () -> Dependency.get(TunerService.class).addTunable(this, SIZE));
// Watch color inversion and invert the overlay as needed.
- SecureSetting setting = new SecureSetting(mContext, Dependency.get(Dependency.MAIN_HANDLER),
+ SecureSetting setting = new SecureSetting(mContext, mHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
@@ -215,18 +231,38 @@
.start();
}
});
+
+ mOverlay.getViewTreeObserver().addOnPreDrawListener(
+ new ValidatingPreDrawListener(mOverlay));
+ mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
+ new ValidatingPreDrawListener(mBottomOverlay));
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- mPendingRotationChange = false;
- updateOrientation();
- if (shouldDrawCutout() && mOverlay == null) {
- setupDecorations();
- }
+ mHandler.post(() -> {
+ int oldRotation = mRotation;
+ mPendingRotationChange = false;
+ updateOrientation();
+ updateRoundedCornerRadii();
+ if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
+ if (shouldDrawCutout() && mOverlay == null) {
+ setupDecorations();
+ }
+ if (mOverlay != null) {
+ // Updating the layout params ensures that ViewRootImpl will call relayoutWindow(),
+ // which ensures that the forced seamless rotation will end, even if we updated
+ // the rotation before window manager was ready (and was still waiting for sending
+ // the updated rotation).
+ updateLayoutParams();
+ }
+ });
}
- protected void updateOrientation() {
+ private void updateOrientation() {
+ Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(),
+ "must call on " + mHandler.getLooper().getThread()
+ + ", but was " + Thread.currentThread());
if (mPendingRotationChange) {
return;
}
@@ -241,6 +277,26 @@
}
}
+ private void updateRoundedCornerRadii() {
+ final int newRoundedDefault = mContext.getResources().getDimensionPixelSize(
+ R.dimen.rounded_corner_radius);
+ final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
+ R.dimen.rounded_corner_radius_top);
+ final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
+ R.dimen.rounded_corner_radius_bottom);
+
+ final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault
+ || mRoundedDefaultBottom != newRoundedDefaultBottom
+ || mRoundedDefaultTop != newRoundedDefaultTop;
+
+ if (roundedCornersChanged) {
+ mRoundedDefault = newRoundedDefault;
+ mRoundedDefaultTop = newRoundedDefaultTop;
+ mRoundedDefaultBottom = newRoundedDefaultBottom;
+ onTuningChanged(SIZE, null);
+ }
+ }
+
private void updateViews() {
View topLeft = mOverlay.findViewById(R.id.left);
View topRight = mOverlay.findViewById(R.id.right);
@@ -306,7 +362,19 @@
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
}
- private void setupPadding(int padding) {
+
+ private void setupStatusBarPaddingIfNeeded() {
+ // TODO: This should be moved to a more appropriate place, as it is not related to the
+ // screen decorations overlay.
+ int padding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.rounded_corner_content_padding);
+ if (padding != 0) {
+ setupStatusBarPadding(padding);
+ }
+
+ }
+
+ private void setupStatusBarPadding(int padding) {
// Add some padding to all the content near the edge of the screen.
StatusBar sb = getComponent(StatusBar.class);
View statusBar = (sb != null ? sb.getStatusBarWindow() : null);
@@ -375,30 +443,32 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (mOverlay == null) return;
- if (SIZE.equals(key)) {
- int size = mRoundedDefault;
- int sizeTop = mRoundedDefaultTop;
- int sizeBottom = mRoundedDefaultBottom;
- if (newValue != null) {
- try {
- size = (int) (Integer.parseInt(newValue) * mDensity);
- } catch (Exception e) {
+ mHandler.post(() -> {
+ if (mOverlay == null) return;
+ if (SIZE.equals(key)) {
+ int size = mRoundedDefault;
+ int sizeTop = mRoundedDefaultTop;
+ int sizeBottom = mRoundedDefaultBottom;
+ if (newValue != null) {
+ try {
+ size = (int) (Integer.parseInt(newValue) * mDensity);
+ } catch (Exception e) {
+ }
}
- }
- if (sizeTop == 0) {
- sizeTop = size;
- }
- if (sizeBottom == 0) {
- sizeBottom = size;
- }
+ if (sizeTop == 0) {
+ sizeTop = size;
+ }
+ if (sizeBottom == 0) {
+ sizeBottom = size;
+ }
- setSize(mOverlay.findViewById(R.id.left), sizeTop);
- setSize(mOverlay.findViewById(R.id.right), sizeTop);
- setSize(mBottomOverlay.findViewById(R.id.left), sizeBottom);
- setSize(mBottomOverlay.findViewById(R.id.right), sizeBottom);
- }
+ setSize(mOverlay.findViewById(R.id.left), sizeTop);
+ setSize(mOverlay.findViewById(R.id.right), sizeTop);
+ setSize(mBottomOverlay.findViewById(R.id.left), sizeBottom);
+ setSize(mBottomOverlay.findViewById(R.id.right), sizeBottom);
+ }
+ });
}
private void setSize(View view, int pixelSize) {
@@ -457,6 +527,11 @@
mVisibilityChangedListener = visibilityChangedListener;
mDecorations = decorations;
setId(R.id.display_cutout);
+ if (DEBUG) {
+ getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
+ (mInitialStart ? "OverlayTop" : "OverlayBottom")
+ + " drawn in rot " + mRotation));
+ }
}
public void setColor(int color) {
@@ -692,20 +767,66 @@
private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
private final View mView;
+ private final int mTargetRotation;
- private RestartingPreDrawListener(View view) {
+ private RestartingPreDrawListener(View view, int targetRotation) {
+ mView = view;
+ mTargetRotation = targetRotation;
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ mView.getViewTreeObserver().removeOnPreDrawListener(this);
+
+ if (mTargetRotation == mRotation) {
+ if (DEBUG) {
+ Log.i(TAG, (mView == mOverlay ? "OverlayTop" : "OverlayBottom")
+ + " already in target rot "
+ + mTargetRotation + ", allow draw without restarting it");
+ }
+ return true;
+ }
+
+ mPendingRotationChange = false;
+ // This changes the window attributes - we need to restart the traversal for them to
+ // take effect.
+ updateOrientation();
+ if (DEBUG) {
+ Log.i(TAG, (mView == mOverlay ? "OverlayTop" : "OverlayBottom")
+ + " restarting listener fired, restarting draw for rot " + mRotation);
+ }
+ mView.invalidate();
+ return false;
+ }
+ }
+
+ /**
+ * A pre-draw listener, that validates that the rotation we draw in matches the displays
+ * rotation before continuing the draw.
+ *
+ * This is to prevent a race condition, where we have not received the display changed event
+ * yet, and would thus draw in an old orientation.
+ */
+ private class ValidatingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
+
+ private final View mView;
+
+ public ValidatingPreDrawListener(View view) {
mView = view;
}
@Override
public boolean onPreDraw() {
- mPendingRotationChange = false;
- mView.getViewTreeObserver().removeOnPreDrawListener(this);
- // This changes the window attributes - we need to restart the traversal for them to
- // take effect.
- updateOrientation();
- mView.invalidate();
- return false;
+ final int displayRotation = RotationUtils.getExactRotation(mContext);
+ if (displayRotation != mRotation && !mPendingRotationChange) {
+ if (DEBUG) {
+ Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+ + displayRotation + ". Restarting draw");
+ }
+ mView.invalidate();
+ return false;
+ }
+ return true;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 89688fb..33db2c8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1647,7 +1647,6 @@
resetKeyguardDonePendingLocked();
}
- mUpdateMonitor.clearFailedUnlockAttempts();
mUpdateMonitor.clearFingerprintRecognized();
if (mGoingToSleep) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index da41136..2e5eb34 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -266,9 +266,12 @@
|| mEstimate.estimateMillis < mSevereWarningThreshold) {
nb.setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
}
- nb.addAction(0,
- mContext.getString(R.string.battery_saver_start_action),
- pendingBroadcast(ACTION_START_SAVER));
+
+ if (!mPowerMan.isPowerSaveMode()) {
+ nb.addAction(0,
+ mContext.getString(R.string.battery_saver_start_action),
+ pendingBroadcast(ACTION_START_SAVER));
+ }
nb.setOnlyAlertOnce(!mPlaySound);
mPlaySound = false;
SystemUI.overrideNotificationAppName(mContext, nb, false);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 9a648d1..0b9067e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -333,10 +333,11 @@
@VisibleForTesting
boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
long timeRemaining, boolean isPowerSaver) {
- final boolean hybridWouldDismiss = mEnhancedEstimates.isHybridNotificationEnabled()
+ final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
+ final boolean hybridWouldDismiss = hybridEnabled
&& timeRemaining > mEnhancedEstimates.getLowWarningThreshold();
final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0);
- return isPowerSaver
+ return (isPowerSaver && !hybridEnabled)
|| plugged
|| (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled()
|| hybridWouldDismiss));
@@ -344,14 +345,14 @@
private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver,
int batteryStatus) {
- if (plugged || isPowerSaver || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+ if (plugged || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return false;
}
int warnLevel = mLowBatteryReminderLevels[0];
int critLevel = mLowBatteryReminderLevels[1];
- // Only show the low warning once per charge cycle
- final boolean canShowWarning = !mLowWarningShownThisChargeCycle
+ // Only show the low warning once per charge cycle & no battery saver
+ final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver
&& (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
|| mBatteryLevel <= warnLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0876a5d..3fc258b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -285,9 +285,6 @@
updatePageIndicator();
- for (TileRecord r : mRecords) {
- r.tile.clearState();
- }
if (mListening) {
refreshAllTiles();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 53a576d..591e9e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -95,7 +95,6 @@
continue;
}
tile.setListening(this, true);
- tile.clearState();
tile.refreshState();
tile.setListening(this, false);
tile.setTileSpec(spec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 834feb7..022a2b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -211,10 +211,6 @@
mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
}
- public void clearState() {
- mHandler.sendEmptyMessage(H.CLEAR_STATE);
- }
-
public void userSwitch(int newUserId) {
mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
}
@@ -266,11 +262,6 @@
public abstract Intent getLongClickIntent();
- protected void handleClearState() {
- mTmpState = newTileState();
- mState = newTileState();
- }
-
protected void handleRefreshState(Object arg) {
handleUpdateState(mTmpState, arg);
final boolean changed = mTmpState.copyTo(mState);
@@ -409,11 +400,10 @@
private static final int TOGGLE_STATE_CHANGED = 8;
private static final int SCAN_STATE_CHANGED = 9;
private static final int DESTROY = 10;
- private static final int CLEAR_STATE = 11;
- private static final int REMOVE_CALLBACKS = 12;
- private static final int REMOVE_CALLBACK = 13;
- private static final int SET_LISTENING = 14;
- private static final int STALE = 15;
+ private static final int REMOVE_CALLBACKS = 11;
+ private static final int REMOVE_CALLBACK = 12;
+ private static final int SET_LISTENING = 13;
+ private static final int STALE = 14;
@VisibleForTesting
protected H(Looper looper) {
@@ -467,9 +457,6 @@
} else if (msg.what == DESTROY) {
name = "handleDestroy";
handleDestroy();
- } else if (msg.what == CLEAR_STATE) {
- name = "handleClearState";
- handleClearState();
} else if (msg.what == SET_LISTENING) {
name = "handleSetListeningInternal";
handleSetListeningInternal(msg.obj, msg.arg1 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 06f26c9..469c3c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -667,9 +667,15 @@
entry.row.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow row = notificationChildren.get(i);
- if ((row.getStatusBarNotification().getNotification().flags
- & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
- // the child is a foreground service notification which we can't remove!
+ NotificationData.Entry childEntry = row.getEntry();
+ boolean isForeground = (row.getStatusBarNotification().getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE) != 0;
+ boolean keepForReply = FORCE_REMOTE_INPUT_HISTORY
+ && (shouldKeepForRemoteInput(childEntry)
+ || shouldKeepForSmartReply(childEntry));
+ if (isForeground || keepForReply) {
+ // the child is a foreground service notification which we can't remove or it's
+ // a child we're keeping around for reply!
continue;
}
row.setKeepInParent(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3063199..a215ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -151,12 +151,11 @@
}
public void fadeInTranslating() {
- float translation = mShelfIcons.getTranslationY();
- mShelfIcons.setTranslationY(translation - mShelfAppearTranslation);
+ mShelfIcons.setTranslationY(-mShelfAppearTranslation);
mShelfIcons.setAlpha(0);
mShelfIcons.animate()
.setInterpolator(Interpolators.DECELERATE_QUINT)
- .translationY(translation)
+ .translationY(0)
.setDuration(SHELF_IN_TRANSLATION_DURATION)
.start();
mShelfIcons.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 7e6abe9..5c18782 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1358,9 +1358,7 @@
mQsExpansionHeight = height;
updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
- if (mKeyguardShowing) {
- updateHeaderKeyguardAlpha();
- }
+ updateHeaderKeyguardAlpha();
if (mStatusBarState == StatusBarState.SHADE_LOCKED
|| mStatusBarState == StatusBarState.KEYGUARD) {
updateKeyguardBottomAreaAlpha();
@@ -1763,6 +1761,9 @@
}
private void updateHeaderKeyguardAlpha() {
+ if (!mKeyguardShowing) {
+ return;
+ }
float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
* mKeyguardStatusBarAnimateAlpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index bd73a40..d68e2fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -189,7 +189,7 @@
mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
&& !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
- return false;
+ return deadZoneConsumed;
}
mNavigationBarView.requestUnbufferedDispatch(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index fadc0ea..a38328a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -180,6 +180,15 @@
mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
}
+ private void applyExpandedFlag(State state) {
+ if (state.panelExpanded || state.isKeyguardShowingAndNotOccluded() || state.bouncerShowing
+ || ENABLE_REMOTE_INPUT && state.remoteInputActive) {
+ mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_BAR_EXPANDED;
+ } else {
+ mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_BAR_EXPANDED;
+ }
+ }
+
private void applyHeight(State state) {
boolean expanded = isExpanded(state);
if (state.forcePluginOpen) {
@@ -234,6 +243,7 @@
applyKeyguardFlags(state);
applyForceStatusBarVisibleFlag(state);
applyFocusableFlag(state);
+ applyExpandedFlag(state);
adjustScreenOrientation(state);
applyHeight(state);
applyUserActivityTimeout(state);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index d6d0673..3c16329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -134,6 +134,10 @@
@Override
public void setHotspotEnabled(boolean enabled) {
+ if (mWaitingForCallback) {
+ if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for callback.");
+ return;
+ }
if (enabled) {
OnStartTetheringCallback callback = new OnStartTetheringCallback();
mWaitingForCallback = true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
index d7c4bbf..c97095e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
@@ -21,11 +21,13 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
import android.media.AudioManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.WindowManager;
+
import com.android.systemui.statusbar.phone.SystemUIDialog;
abstract public class SafetyWarningDialog extends SystemUIDialog
@@ -40,12 +42,18 @@
private long mShowTime;
private boolean mNewVolumeUp;
+ private boolean mDisableOnVolumeUp;
public SafetyWarningDialog(Context context, AudioManager audioManager) {
super(context);
mContext = context;
mAudioManager = audioManager;
-
+ try {
+ mDisableOnVolumeUp = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_safe_media_disable_on_volume_up);
+ } catch (NotFoundException e) {
+ mDisableOnVolumeUp = true;
+ }
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
setShowForAllUsers(true);
setMessage(mContext.getString(com.android.internal.R.string.safe_media_volume_warning));
@@ -63,7 +71,8 @@
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && event.getRepeatCount() == 0) {
+ if (mDisableOnVolumeUp && keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ && event.getRepeatCount() == 0) {
mNewVolumeUp = true;
}
return super.onKeyDown(keyCode, event);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index f1bf31d..cc96917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -21,6 +21,7 @@
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -34,8 +35,10 @@
import android.app.Fragment;
import android.content.res.Configuration;
+import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.View;
@@ -60,6 +63,7 @@
@SmallTest
public class ScreenDecorationsTest extends SysuiTestCase {
+ private TestableLooper mTestableLooper;
private ScreenDecorations mScreenDecorations;
private StatusBar mStatusBar;
private WindowManager mWindowManager;
@@ -71,6 +75,10 @@
@Before
public void setup() {
+ mTestableLooper = TestableLooper.get(this);
+ mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+ new Handler(mTestableLooper.getLooper()));
+
mStatusBar = mock(StatusBar.class);
mWindowManager = mock(WindowManager.class);
mView = spy(new StatusBarWindowView(mContext, null));
@@ -88,7 +96,31 @@
mTunerService = mDependency.injectMockDependency(TunerService.class);
- mScreenDecorations = new ScreenDecorations();
+
+ mScreenDecorations = new ScreenDecorations() {
+ @Override
+ public void start() {
+ super.start();
+ mTestableLooper.processAllMessages();
+ }
+
+ @Override
+ Handler startHandlerThread() {
+ return new Handler(mTestableLooper.getLooper());
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mTestableLooper.processAllMessages();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ super.onTuningChanged(key, newValue);
+ mTestableLooper.processAllMessages();
+ }
+ };
mScreenDecorations.mContext = mContext;
mScreenDecorations.mComponents = mContext.getComponents();
@@ -195,4 +227,17 @@
verify(padding).destroy();
}
+ @Test
+ public void testUpdateRoundedCorners() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
+ mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
+
+ mScreenDecorations.start();
+ assertEquals(mScreenDecorations.mRoundedDefault, 20);
+
+ mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 5);
+ mScreenDecorations.onConfigurationChanged(null);
+ assertEquals(mScreenDecorations.mRoundedDefault, 5);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 5ecf0c0..a9d49f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -323,9 +323,9 @@
}
@Test
- public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabled() {
+ public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabledLegacy() {
mPowerUI.start();
- when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+ when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(false);
when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
@@ -337,6 +337,20 @@
}
@Test
+ public void testShouldNotDismissLowBatteryWarning_dismissWhenPowerSaverEnabledHybrid() {
+ mPowerUI.start();
+ when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+ when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
+ when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+
+ // device that gets power saver turned on should dismiss
+ boolean shouldDismiss =
+ mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+ BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, !POWER_SAVER_OFF);
+ assertFalse(shouldDismiss);
+ }
+
+ @Test
public void testShouldDismissLowBatteryWarning_dismissWhenPlugged() {
mPowerUI.start();
when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml
index 754ba72..b08924b 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay">Corner display cutout</string>
+ <string name="display_cutout_emulation_overlay">Corner cutout</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
index 68c2dcb..0a106fa 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay">Double display cutout</string>
+ <string name="display_cutout_emulation_overlay">Double cutout</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml
index 4989677..0bf8330 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml
@@ -18,7 +18,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay">Narrow display cutout</string>
+ <string name="display_cutout_emulation_overlay">Narrow cutout</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml
index 6dcbbd9..bcc7c97 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay">Tall display cutout</string>
+ <string name="display_cutout_emulation_overlay">Tall cutout</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml
index f4b9f7e..0fcbdebb 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay">Wide display cutout</string>
+ <string name="display_cutout_emulation_overlay">Wide cutout</string>
</resources>
diff --git a/proto/src/gnss.proto b/proto/src/gnss.proto
index 0168392..1509fc0 100644
--- a/proto/src/gnss.proto
+++ b/proto/src/gnss.proto
@@ -45,6 +45,9 @@
// Power metrics
optional PowerMetrics power_metrics = 12;
+
+ // Hardware revision (EVT, DVT, PVT etc.)
+ optional string hardware_revision = 13;
}
// Power metrics
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 143fa86..0833e34 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -941,9 +941,10 @@
// OS: 6.0
NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
- // ACTION: App notification settings > Block Notifications
+ // ACTION: App notification settings > Block Notifications or long press on
+ // notification blocks.
// CATEGORY: SETTINGS
- // OS: 6.0
+ // OS: 9.0
ACTION_BAN_APP_NOTES = 147;
// ACTION: Notification shade > Dismiss all button
@@ -6129,6 +6130,305 @@
// CATEGORY: NOTIFICATION
NOTIFICATION_INTERRUPTION = 1501;
+ // OPEN: Settings
+ // CATEGORY: SETTINGS
+ // OS: Q
+ SETTINGS_HOMEPAGE = 1502;
+
+ // OPEN: Settings > Create shortcut(widget)
+ // CATEGORY: SETTINGS
+ // OS: Q
+ SETTINGS_CREATE_SHORTCUT = 1503;
+
+ // ACTION: Authenticate using fingerprint
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACTION_FACE_AUTH = 1504;
+
+ // ACTION: Add fingerprint > Enroll fingerprint
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACTION_FACE_ENROLL = 1505;
+
+ // OPEN: Face Enroll introduction
+ // CATEGORY: SETTINGS
+ // OS: Q
+ FACE_ENROLL_INTRO = 1506;
+
+ // OPEN: Face Enroll introduction
+ // CATEGORY: SETTINGS
+ // OS: Q
+ FACE_ENROLL_ENROLLING = 1507;
+
+ // OPEN: Face Enroll introduction
+ // CATEGORY: SETTINGS
+ // OS: Q
+ FACE_ENROLL_FINISHED = 1508;
+
+ // OPEN: Face Enroll sidecar
+ // CATEGORY: SETTINGS
+ // OS: Q
+ FACE_ENROLL_SIDECAR = 1509;
+
+ // OPEN: Settings > Add face > Error dialog
+ // OS: Q
+ DIALOG_FACE_ERROR = 1510;
+
+ // OPEN: Settings > Security > Face
+ // CATEGORY: SETTINGS
+ // OS: Q
+ FACE = 1511;
+
+ // OPEN: Settings > Acessibility > HearingAid pairing instructions dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ DIALOG_ACCESSIBILITY_HEARINGAID = 1512;
+
+ // ACTION: Activity start
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ ACTION_ACTIVITY_START = 1513;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Calling UID
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_CALLING_UID = 1514;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Calling package name
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_CALLING_PACKAGE_NAME = 1515;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Calling UID proc state
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_CALLING_UID_PROC_STATE = 1516;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Calling UID has any visible window
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW = 1517;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Real calling UID
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_REAL_CALLING_UID = 1518;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Real calling UID proc state
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_REAL_CALLING_UID_PROC_STATE = 1519;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Real calling UID has any visible window
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW = 1520;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Target UID
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_TARGET_UID = 1521;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Target UID package name
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_TARGET_PACKAGE_NAME = 1522;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Target UID proc state
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_TARGET_UID_PROC_STATE = 1523;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Target UID has any visible window
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW = 1524;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Target doze whitelist tag
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_TARGET_WHITELIST_TAG = 1525;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Target short component name
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_TARGET_SHORT_COMPONENT_NAME = 1526;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Coming from pending intent
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_COMING_FROM_PENDING_INTENT = 1527;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Intent action
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_INTENT_ACTION = 1528;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record process name
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_PROCESS_NAME = 1529;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record current proc state
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_CUR_PROC_STATE = 1530;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record has client activities
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES = 1531;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record has foreground services
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES = 1532;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record has foreground activities
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES = 1533;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record has top UI
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_HAS_TOP_UI = 1534;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record has overlay UI
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_HAS_OVERLAY_UI = 1535;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Caller app process record pending UI clean
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_PENDING_UI_CLEAN = 1536;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Millis since caller app's process record last interaction event
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT = 1537;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Millis since caller app's process record fg interaction
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION = 1538;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Millis since caller app's process record last became unimportant
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT = 1539;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record launch mode
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_LAUNCH_MODE = 1540;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record target activity
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY = 1541;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record flags
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_FLAGS = 1542;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record real activity
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_REAL_ACTIVITY = 1543;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record short component name
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME = 1544;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record process name
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_PROCESS_NAME = 1545;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record is fullscreen
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_IS_FULLSCREEN = 1546;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record is no display
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY = 1547;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Millis since activity was last visible
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE = 1548;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record's resultTo packageName
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME = 1549;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record's resultTo shortComponentName
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME = 1550;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record is visible
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_IS_VISIBLE = 1551;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Activity record is visible ignoring keyguard
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD = 1552;
+
+ // Tagged data for ACTION_ACTIVITY_START.
+ // FIELD: Millis since activity's last launch
+ // CATEGORY: OTHER
+ // OS: Q (will also ship in PQ1A)
+ FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH = 1553;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 72f11e0..b29c992 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -457,6 +457,11 @@
// Identifier for experimental scoring parameter settings.
optional string score_experiment_id = 117;
+ // Histogram of the EAP method type of all installed Passpoint profiles
+ repeated PasspointProfileTypeCount installed_passpoint_profile_type = 123;
+
+ // Hardware revision (EVT, DVT, PVT etc.)
+ optional string hardware_revision = 124;
}
// Information that gets logged for every WiFi connection.
@@ -1503,3 +1508,31 @@
optional int32 count = 2;
}
}
+
+message PasspointProfileTypeCount {
+ enum EapMethod {
+ // Unknown Type
+ TYPE_UNKNOWN = 0;
+
+ // EAP_TLS (13)
+ TYPE_EAP_TLS = 1;
+
+ // EAP_TTLS (21)
+ TYPE_EAP_TTLS = 2;
+
+ // EAP_SIM (18)
+ TYPE_EAP_SIM = 3;
+
+ // EAP_AKA (23)
+ TYPE_EAP_AKA = 4;
+
+ // EAP_AKA_PRIME (50)
+ TYPE_EAP_AKA_PRIME = 5;
+ }
+
+ // Eap method type set in Passpoint profile
+ optional EapMethod eap_method_type = 1;
+
+ // Num of installed Passpoint profile with same eap method
+ optional int32 count = 2;
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index c9c7adc..f69b638 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -48,11 +48,6 @@
}
@Override
- public void onUnlockUser(int userHandle) {
- FgThread.getHandler().post(() -> mImpl.onUserUnlocked(userHandle));
- }
-
- @Override
public void onStopUser(int userHandle) {
mImpl.onUserStopped(userHandle);
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index db8ad12..b71d7a7 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,7 +19,6 @@
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.UserIdInt;
@@ -2697,7 +2696,12 @@
}
}
- void onUserUnlocked(int userId) {
+ /**
+ * This does not use the usual onUserUnlocked() listener mechanism because it is
+ * invoked at a choreographed point in the middle of the user unlock sequence,
+ * before the boot-completed broadcast is issued and the listeners notified.
+ */
+ void handleUserUnlocked(int userId) {
if (isProfileWithLockedParent(userId)) {
return;
}
@@ -2734,7 +2738,7 @@
}
}
}
- Slog.i(TAG, "Async processing of onUserUnlocked u" + userId + " took "
+ Slog.i(TAG, "Processing of handleUserUnlocked u" + userId + " took "
+ (SystemClock.elapsedRealtime() - time) + " ms");
}
@@ -4801,5 +4805,11 @@
return widgetPackages;
}
}
+
+ @Override
+ public void unlockUser(int userId) {
+ handleUserUnlocked(userId);
+ }
+
}
}
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 dc84498..5882303 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -81,6 +81,13 @@
void onDestroy();
}
+ /**
+ * Wrapper that guarantees that only one callback is triggered by ignoring further calls after
+ * it's destroyed.
+ *
+ * <p>It's needed becase {@link #onCancel(IntentSender)} is always called when the Save UI
+ * dialog is dismissed.
+ */
private class OneTimeListener implements OnSaveListener {
private final OnSaveListener mRealListener;
@@ -96,7 +103,6 @@
if (mDone) {
return;
}
- mDone = true;
mRealListener.onSave();
}
@@ -106,7 +112,6 @@
if (mDone) {
return;
}
- mDone = true;
mRealListener.onCancel(listener);
}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 5c14459..50f15ca0 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -624,7 +624,7 @@
// them will get the new sequence number at that point. (See for example how testing
// of JobScheduler's BatteryController works.)
sendBatteryChangedIntentLocked();
- if (mLastBatteryLevel != mHealthInfo.batteryLevel) {
+ if (mLastBatteryLevel != mHealthInfo.batteryLevel || mLastPlugType != mPlugType) {
sendBatteryLevelChangedIntentLocked();
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index f5b29e9..0deaee7 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -43,6 +43,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.MediaStore;
import android.provider.Settings;
import android.system.ErrnoException;
@@ -69,6 +70,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.ArrayList;
import java.util.zip.ZipFile;
@@ -103,6 +105,7 @@
private final Context mContext;
private final ActivityManagerInternal mAmInternal;
private final IActivityManager mAm;
+ private final UserManager mUserManager;
/** The list of the statically pinned files. */
@GuardedBy("this")
@@ -164,6 +167,8 @@
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mAm = ActivityManager.getService();
+ mUserManager = mContext.getSystemService(UserManager.class);
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addDataScheme("package");
@@ -194,12 +199,16 @@
*/
@Override
public void onSwitchUser(int userHandle) {
- sendPinAppsMessage(userHandle);
+ if (!mUserManager.isManagedProfile(userHandle)) {
+ sendPinAppsMessage(userHandle);
+ }
}
@Override
public void onUnlockUser(int userHandle) {
- sendPinAppsMessage(userHandle);
+ if (!mUserManager.isManagedProfile(userHandle)) {
+ sendPinAppsMessage(userHandle);
+ }
}
/**
@@ -345,31 +354,76 @@
}
private ApplicationInfo getCameraInfo(int userHandle) {
- // find the camera via an intent
- // use INTENT_ACTION_STILL_IMAGE_CAMERA instead of _SECURE. On a
- // device without a fbe enabled, the _SECURE intent will never get set.
Intent cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
- return getApplicationInfoForIntent(cameraIntent, userHandle);
+ ApplicationInfo info = getApplicationInfoForIntent(cameraIntent, userHandle,
+ false /* defaultToSystemApp */);
+
+ // If the STILL_IMAGE_CAMERA intent doesn't resolve, try the _SECURE intent.
+ // We don't use _SECURE first because it will never get set on a device
+ // without File-based Encryption. But if the user has only set the intent
+ // before unlocking their device, we may still be able to identify their
+ // preference using this intent.
+ if (info == null) {
+ cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+ info = getApplicationInfoForIntent(cameraIntent, userHandle,
+ false /* defaultToSystemApp */);
+ }
+
+ // If the _SECURE intent doesn't resolve, try the original intent but request
+ // the system app for camera if there was more than one result.
+ if (info == null) {
+ cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ info = getApplicationInfoForIntent(cameraIntent, userHandle,
+ true /* defaultToSystemApp */);
+ }
+ return info;
}
private ApplicationInfo getHomeInfo(int userHandle) {
Intent intent = mAmInternal.getHomeIntent();
- return getApplicationInfoForIntent(intent, userHandle);
+ return getApplicationInfoForIntent(intent, userHandle, false);
}
- private ApplicationInfo getApplicationInfoForIntent(Intent intent, int userHandle) {
+ private ApplicationInfo getApplicationInfoForIntent(Intent intent, int userHandle,
+ boolean defaultToSystemApp) {
if (intent == null) {
return null;
}
- ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(intent,
+
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(intent,
MATCH_FLAGS, userHandle);
- if (info == null) {
+
+ // If this intent can resolve to only one app, choose that one.
+ // Otherwise, if we've requested to default to the system app, return it;
+ // if we have not requested that default, return null if there's more than one option.
+ // If there's more than one system app, return null since we don't know which to pick.
+ if (resolveInfo == null) {
return null;
}
- if (isResolverActivity(info.activityInfo)) {
- return null;
+
+ if (!isResolverActivity(resolveInfo.activityInfo)) {
+ return resolveInfo.activityInfo.applicationInfo;
}
- return info.activityInfo.applicationInfo;
+
+ if (defaultToSystemApp) {
+ List<ResolveInfo> infoList = mContext.getPackageManager()
+ .queryIntentActivitiesAsUser(intent, MATCH_FLAGS, userHandle);
+ ApplicationInfo systemAppInfo = null;
+ for (ResolveInfo info : infoList) {
+ if ((info.activityInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (systemAppInfo == null) {
+ systemAppInfo = info.activityInfo.applicationInfo;
+ } else {
+ // If there's more than one system app, return null due to ambiguity.
+ return null;
+ }
+ }
+ }
+ return systemAppInfo;
+ }
+
+ return null;
}
private void sendPinAppsMessage(int userHandle) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 6550d06..9bf72fb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -207,6 +207,10 @@
// Indicates if the processes need to be started asynchronously.
public boolean FLAG_PROCESS_START_ASYNC = DEFAULT_PROCESS_START_ASYNC;
+ // Indicates whether the activity starts logging is enabled.
+ // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
+ boolean mFlagActivityStartsLoggingEnabled;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -235,6 +239,12 @@
// memory trimming.
public int CUR_TRIM_CACHED_PROCESSES;
+ private static final Uri ACTIVITY_MANAGER_CONSTANTS_URI = Settings.Global.getUriFor(
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS);
+
+ private static final Uri ACTIVITY_STARTS_LOGGING_ENABLED_URI = Settings.Global.getUriFor(
+ Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED);
+
public ActivityManagerConstants(ActivityManagerService service, Handler handler) {
super(handler);
mService = service;
@@ -243,9 +253,10 @@
public void start(ContentResolver resolver) {
mResolver = resolver;
- mResolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.ACTIVITY_MANAGER_CONSTANTS), false, this);
+ mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this);
+ mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
updateConstants();
+ updateActivityStartsLoggingEnabled();
}
public void setOverrideMaxCachedProcesses(int value) {
@@ -263,7 +274,12 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- updateConstants();
+ if (uri == null) return;
+ if (ACTIVITY_MANAGER_CONSTANTS_URI.equals(uri)) {
+ updateConstants();
+ } else if (ACTIVITY_STARTS_LOGGING_ENABLED_URI.equals(uri)) {
+ updateActivityStartsLoggingEnabled();
+ }
}
private void updateConstants() {
@@ -337,6 +353,11 @@
}
}
+ private void updateActivityStartsLoggingEnabled() {
+ mFlagActivityStartsLoggingEnabled = Settings.Global.getInt(mResolver,
+ Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 0) == 1;
+ }
+
private void updateMaxCachedProcesses() {
CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c3782d0..e895c14 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5591,7 +5591,7 @@
// TODO: Switch to user app stacks here.
int ret = mActivityStartController.startActivities(caller, -1, callingPackage,
intents, resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId,
- reason);
+ reason, null /* originatingPendingIntent */);
return ret;
}
@@ -9498,10 +9498,17 @@
}
}
- // If we're extending a persistable grant, then we always need to create
- // the grant data structure so that take/release APIs work
+ // Figure out the value returned when access is allowed
+ final int allowedResult;
if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
- return targetUid;
+ // If we're extending a persistable grant, then we need to return
+ // "targetUid" so that we always create a grant data structure to
+ // support take/release APIs
+ allowedResult = targetUid;
+ } else {
+ // Otherwise, we can return "-1" to indicate that no grant data
+ // structures need to be created
+ allowedResult = -1;
}
if (targetUid >= 0) {
@@ -9510,7 +9517,7 @@
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Target " + targetPkg + " already has full permission to " + grantUri);
- return -1;
+ return allowedResult;
}
} else {
// First... there is no target package, so can anyone access it?
@@ -9545,7 +9552,7 @@
}
}
if (allowed) {
- return -1;
+ return allowedResult;
}
}
@@ -10927,6 +10934,20 @@
}
}
+ /**
+ * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
+ * the whitelist
+ */
+ String getPendingTempWhitelistTagForUidLocked(int uid) {
+ final PendingTempWhitelist ptw = mPendingTempWhitelist.get(uid);
+ return ptw != null ? ptw.tag : null;
+ }
+
+ @VisibleForTesting
+ boolean isActivityStartsLoggingEnabled() {
+ return mConstants.mFlagActivityStartsLoggingEnabled;
+ }
+
@Override
public void moveStackToDisplay(int stackId, int displayId) {
enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
@@ -26379,7 +26400,7 @@
packageUid, packageName,
intents, resolvedTypes, null /* resultTo */,
SafeActivityOptions.fromBundle(bOptions), userId,
- false /* validateIncomingUser */);
+ false /* validateIncomingUser */, null /* originatingPendingIntent */);
}
}
@@ -26718,6 +26739,18 @@
return ActivityManagerService.this.getHomeIntent();
}
}
+
+ @Override
+ public void notifyDefaultDisplaySizeChanged() {
+ synchronized (ActivityManagerService.this) {
+ if (mSystemServiceManager.isBootCompleted() && mHomeProcess != null) {
+
+ // TODO: Ugly hack to unblock the release
+ Slog.i(TAG, "Killing home process because of display size change");
+ removeProcessLocked(mHomeProcess, false, true, "kill home screen size");
+ }
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index dc9a5adb..093bd87 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2844,6 +2844,7 @@
pw.println(" --checkin: output checkin format, resetting data.");
pw.println(" --C: output checkin format, not resetting data.");
pw.println(" --proto: output dump in protocol buffer format.");
+ pw.println(" --autofill: dump just the autofill-related state of an activity");
} else {
pw.println("Activity manager (activity) commands:");
pw.println(" help");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 47d0423..9ffa662 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -2,6 +2,7 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.processStateAmToProto;
import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -9,6 +10,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ACTIVITY_START;
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;
@@ -21,8 +23,48 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_FLAGS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_FULLSCREEN;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_LAUNCH_MODE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_PROCESS_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_REAL_ACTIVITY;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_PACKAGE_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_PROC_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_COMING_FROM_PENDING_INTENT;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INTENT_ACTION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_CUR_PROC_STATE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_OVERLAY_UI;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_TOP_UI;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PENDING_UI_CLEAN;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PROCESS_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_PACKAGE_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_SHORT_COMPONENT_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_PROC_STATE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_WHITELIST_TAG;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_FILTER;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
@@ -37,6 +79,7 @@
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.dex.ArtManagerInternal;
import android.content.pm.dex.PackageOptimizationInfo;
@@ -622,6 +665,95 @@
startupTimeMs);
}
+ void logActivityStart(Intent intent, ProcessRecord callerApp, ActivityRecord r,
+ int callingUid, String callingPackage, int callingUidProcState,
+ boolean callingUidHasAnyVisibleWindow,
+ int realCallingUid, int realCallingUidProcState,
+ boolean realCallingUidHasAnyVisibleWindow,
+ int targetUid, String targetPackage, int targetUidProcState,
+ boolean targetUidHasAnyVisibleWindow, String targetWhitelistTag,
+ boolean comingFromPendingIntent) {
+
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowUptime = SystemClock.uptimeMillis();
+ final LogMaker builder = new LogMaker(ACTION_ACTIVITY_START);
+ builder.setTimestamp(System.currentTimeMillis());
+ builder.addTaggedData(FIELD_CALLING_UID, callingUid);
+ builder.addTaggedData(FIELD_CALLING_PACKAGE_NAME, callingPackage);
+ builder.addTaggedData(FIELD_CALLING_UID_PROC_STATE,
+ processStateAmToProto(callingUidProcState));
+ builder.addTaggedData(FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
+ callingUidHasAnyVisibleWindow ? 1 : 0);
+ builder.addTaggedData(FIELD_REAL_CALLING_UID, realCallingUid);
+ builder.addTaggedData(FIELD_REAL_CALLING_UID_PROC_STATE,
+ processStateAmToProto(realCallingUidProcState));
+ builder.addTaggedData(FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
+ realCallingUidHasAnyVisibleWindow ? 1 : 0);
+ builder.addTaggedData(FIELD_TARGET_UID, targetUid);
+ builder.addTaggedData(FIELD_TARGET_PACKAGE_NAME, targetPackage);
+ builder.addTaggedData(FIELD_TARGET_UID_PROC_STATE,
+ processStateAmToProto(targetUidProcState));
+ builder.addTaggedData(FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW,
+ targetUidHasAnyVisibleWindow ? 1 : 0);
+ builder.addTaggedData(FIELD_TARGET_WHITELIST_TAG, targetWhitelistTag);
+ builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME, r.shortComponentName);
+ builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
+ builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
+ if (callerApp != null) {
+ builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.processName);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_CUR_PROC_STATE,
+ processStateAmToProto(callerApp.curProcState));
+ builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES,
+ callerApp.hasClientActivities ? 1 : 0);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES,
+ callerApp.hasForegroundServices() ? 1 : 0);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES,
+ callerApp.foregroundActivities ? 1 : 0);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_TOP_UI, callerApp.hasTopUi ? 1 : 0);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_OVERLAY_UI,
+ callerApp.hasOverlayUi ? 1 : 0);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_PENDING_UI_CLEAN,
+ callerApp.pendingUiClean ? 1 : 0);
+ if (callerApp.interactionEventTime != 0) {
+ builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT,
+ (nowElapsed - callerApp.interactionEventTime));
+ }
+ if (callerApp.fgInteractionTime != 0) {
+ builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION,
+ (nowElapsed - callerApp.fgInteractionTime));
+ }
+ if (callerApp.whenUnimportant != 0) {
+ builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT,
+ (nowUptime - callerApp.whenUnimportant));
+ }
+ }
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_LAUNCH_MODE, r.info.launchMode);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY, r.info.targetActivity);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_FLAGS, r.info.flags);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_REAL_ACTIVITY, r.realActivity.toShortString());
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME, r.shortComponentName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_PROCESS_NAME, r.processName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_FULLSCREEN, r.fullscreen ? 1 : 0);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY, r.noDisplay ? 1 : 0);
+ if (r.lastVisibleTime != 0) {
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE,
+ (nowUptime - r.lastVisibleTime));
+ }
+ if (r.resultTo != null) {
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME, r.resultTo.packageName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME,
+ r.resultTo.shortComponentName);
+ }
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE, r.visible ? 1 : 0);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD,
+ r.visibleIgnoringKeyguard ? 1 : 0);
+ if (r.lastLaunchTime != 0) {
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH,
+ (nowUptime - r.lastLaunchTime));
+ }
+ mMetricsLogger.write(builder);
+ }
+
private int getTransitionType(WindowingModeTransitionInfo info) {
if (info.currentTransitionProcessRunning) {
if (info.startResult == START_SUCCESS) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 75f2723..60f79f72 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -694,9 +694,13 @@
final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null;
if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
// Picture-in-picture mode changes also trigger a multi-window mode change as well, so
- // update that here in order
+ // update that here in order. Set the last reported MW state to the same as the PiP
+ // state since we haven't yet actually resized the task (these callbacks need to
+ // preceed the configuration change from the resiez.
+ // TODO(110009072): Once we move these callbacks to the client, remove all logic related
+ // to forcing the update of the picture-in-picture mode as a part of the PiP animation.
mLastReportedPictureInPictureMode = inPictureInPictureMode;
- mLastReportedMultiWindowMode = inMultiWindowMode();
+ mLastReportedMultiWindowMode = inPictureInPictureMode;
final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
targetStackBounds, null);
schedulePictureInPictureModeChanged(newConfig);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c520101..2ae056f 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4853,7 +4853,7 @@
return mService.getActivityStartController().startActivityInPackage(
task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
- false /* validateIncomingUser */);
+ false /* validateIncomingUser */, null /* originatingPendingIntent */);
} finally {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
// If we are launching the task in the docked stack, put it into resizing mode so
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index a7c3200..edcf6e7 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -248,7 +248,8 @@
final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, TaskRecord inTask, String reason, boolean validateIncomingUser) {
+ int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+ PendingIntentRecord originatingPendingIntent) {
userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
reason);
@@ -267,6 +268,7 @@
.setActivityOptions(options)
.setMayWait(userId)
.setInTask(inTask)
+ .setOriginatingPendingIntent(originatingPendingIntent)
.execute();
}
@@ -278,10 +280,12 @@
* @param intents Intents to start.
* @param userId Start the intents on this user.
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
+ * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
+ * null if not originated by PendingIntent
*/
final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
- boolean validateIncomingUser) {
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
final String reason = "startActivityInPackage";
@@ -290,12 +294,12 @@
// TODO: Switch to user app stacks here.
return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options,
- userId, reason);
+ userId, reason, originatingPendingIntent);
}
int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
- int userId, String reason) {
+ int userId, String reason, PendingIntentRecord originatingPendingIntent) {
if (intents == null) {
throw new NullPointerException("intents is null");
}
@@ -374,6 +378,7 @@
// Top activity decides on animation being run, so we allow only for the
// top one as otherwise an activity below might consume it.
.setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/)
+ .setOriginatingPendingIntent(originatingPendingIntent)
.execute();
if (res < 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 73e3d33..00ba3a6 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -99,6 +99,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
@@ -313,6 +314,7 @@
int userId;
WaitResult waitResult;
int filterCallingUid;
+ PendingIntentRecord originatingPendingIntent;
/**
* If set to {@code true}, allows this activity start to look into
@@ -369,6 +371,7 @@
avoidMoveToFront = false;
allowPendingRemoteAnimationRegistryLookup = true;
filterCallingUid = UserHandle.USER_NULL;
+ originatingPendingIntent = null;
}
/**
@@ -407,6 +410,7 @@
allowPendingRemoteAnimationRegistryLookup
= request.allowPendingRemoteAnimationRegistryLookup;
filterCallingUid = request.filterCallingUid;
+ originatingPendingIntent = request.originatingPendingIntent;
}
}
@@ -490,7 +494,8 @@
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
- mRequest.allowPendingRemoteAnimationRegistryLookup);
+ mRequest.allowPendingRemoteAnimationRegistryLookup,
+ mRequest.originatingPendingIntent);
} else {
return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
@@ -500,7 +505,8 @@
mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
mRequest.outActivity, mRequest.inTask, mRequest.reason,
- mRequest.allowPendingRemoteAnimationRegistryLookup);
+ mRequest.allowPendingRemoteAnimationRegistryLookup,
+ mRequest.originatingPendingIntent);
}
} finally {
onExecutionComplete();
@@ -532,7 +538,8 @@
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, TaskRecord inTask, String reason,
- boolean allowPendingRemoteAnimationRegistryLookup) {
+ boolean allowPendingRemoteAnimationRegistryLookup,
+ PendingIntentRecord originatingPendingIntent) {
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
@@ -545,7 +552,7 @@
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
- inTask, allowPendingRemoteAnimationRegistryLookup);
+ inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
if (outActivity != null) {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
@@ -575,7 +582,8 @@
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
- TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
+ TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
+ PendingIntentRecord originatingPendingIntent) {
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
final Bundle verificationBundle
@@ -865,10 +873,58 @@
mController.doPendingActivityLaunches(false);
+ maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp, r,
+ originatingPendingIntent);
+
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity);
}
+ private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
+ Intent intent, ProcessRecord callerApp, ActivityRecord r,
+ PendingIntentRecord originatingPendingIntent) {
+ boolean callerAppHasForegroundActivity = (callerApp != null)
+ ? callerApp.foregroundActivities
+ : false;
+ if (!mService.isActivityStartsLoggingEnabled() || callerAppHasForegroundActivity
+ || r == null) {
+ // skip logging in this case
+ return;
+ }
+
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "logActivityStart");
+ final int callingUidProcState = mService.getUidStateLocked(callingUid);
+ final boolean callingUidHasAnyVisibleWindow =
+ mService.mWindowManager.isAnyWindowVisibleForUid(callingUid);
+ final int realCallingUidProcState = (callingUid == realCallingUid)
+ ? callingUidProcState
+ : mService.getUidStateLocked(realCallingUid);
+ final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
+ ? callingUidHasAnyVisibleWindow
+ : mService.mWindowManager.isAnyWindowVisibleForUid(realCallingUid);
+ final String targetPackage = r.packageName;
+ final int targetUid = (r.appInfo != null) ? r.appInfo.uid : -1;
+ final int targetUidProcState = mService.getUidStateLocked(targetUid);
+ final boolean targetUidHasAnyVisibleWindow = (targetUid != -1)
+ ? mService.mWindowManager.isAnyWindowVisibleForUid(targetUid)
+ : false;
+ final String targetWhitelistTag = (targetUid != -1)
+ ? mService.getPendingTempWhitelistTagForUidLocked(targetUid)
+ : null;
+
+ mSupervisor.getActivityMetricsLogger().logActivityStart(intent, callerApp, r,
+ callingUid, callingPackage, callingUidProcState,
+ callingUidHasAnyVisibleWindow,
+ realCallingUid, realCallingUidProcState,
+ realCallingUidHasAnyVisibleWindow,
+ targetUid, targetPackage, targetUidProcState,
+ targetUidHasAnyVisibleWindow, targetWhitelistTag,
+ (originatingPendingIntent != null));
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
/**
* Creates a launch intent for the given auxiliary resolution data.
@@ -949,7 +1005,8 @@
ProfilerInfo profilerInfo, WaitResult outResult,
Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
int userId, TaskRecord inTask, String reason,
- boolean allowPendingRemoteAnimationRegistryLookup) {
+ boolean allowPendingRemoteAnimationRegistryLookup,
+ PendingIntentRecord originatingPendingIntent) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -1100,7 +1157,7 @@
voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
- allowPendingRemoteAnimationRegistryLookup);
+ allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
Binder.restoreCallingIdentity(origId);
@@ -2625,6 +2682,11 @@
return this;
}
+ ActivityStarter setOriginatingPendingIntent(PendingIntentRecord originatingPendingIntent) {
+ mRequest.originatingPendingIntent = originatingPendingIntent;
+ return this;
+ }
+
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
pw.print(prefix);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index a6dafbb..f0e2876 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -484,7 +484,8 @@
task.intent, null, null, null, 0, 0,
new SafeActivityOptions(ActivityOptions.makeBasic()),
task.userId, null,
- "AppErrors", false /*validateIncomingUser*/);
+ "AppErrors", false /*validateIncomingUser*/,
+ null /* originatingPendingIntent */);
}
}
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index e0aa2a2..4e00304 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -307,7 +307,7 @@
} else if (finalIntent.getComponent() != null) {
finalIntent.getComponent().appendShortString(tag);
} else if (finalIntent.getData() != null) {
- tag.append(finalIntent.getData());
+ tag.append(finalIntent.getData().toSafeString());
}
owner.tempWhitelistForPendingIntentLocked(callingPid,
callingUid, uid, duration, tag.toString());
@@ -346,13 +346,15 @@
res = owner.getActivityStartController().startActivitiesInPackage(
uid, key.packageName, allIntents, allResolvedTypes,
resultTo, mergedOptions, userId,
- false /* validateIncomingUser */);
+ false /* validateIncomingUser */,
+ this /* originatingPendingIntent */);
} else {
res = owner.getActivityStartController().startActivityInPackage(uid,
callingPid, callingUid, key.packageName, finalIntent,
resolvedType, resultTo, resultWho, requestCode, 0,
mergedOptions, userId, null, "PendingIntentRecord",
- false /* validateIncomingUser */);
+ false /* validateIncomingUser */,
+ this /* originatingPendingIntent */);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index caf52e3..28ebbb8 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -856,4 +856,8 @@
}
return list;
}
+
+ boolean hasForegroundServices() {
+ return foregroundServices;
+ }
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 18c0957..415a822 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -24,7 +24,6 @@
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
-
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -48,6 +47,7 @@
import android.app.IUserSwitchObserver;
import android.app.KeyguardManager;
import android.app.usage.UsageEvents;
+import android.appwidget.AppWidgetManagerInternal;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -87,8 +87,8 @@
import android.util.SparseIntArray;
import android.util.TimingsTraceLog;
import android.util.proto.ProtoOutputStream;
-
import android.view.Window;
+
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -533,6 +533,9 @@
}
}
+ // Spin up app widgets prior to boot-complete, so they can be ready promptly
+ mInjector.startUserWidgets(userId);
+
Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);
// Do not report secondary users, runtime restarts or first boot/upgrade
if (userId == UserHandle.USER_SYSTEM
@@ -2173,6 +2176,13 @@
}
}
+ void startUserWidgets(int userId) {
+ AppWidgetManagerInternal awm = LocalServices.getService(AppWidgetManagerInternal.class);
+ if (awm != null) {
+ awm.unlockUser(userId);
+ }
+ }
+
void updateUserConfiguration() {
synchronized (mService) {
mService.updateUserConfigurationLocked();
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 349e1c8..512e851 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -104,6 +104,12 @@
public static final int FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 10;
/**
+ * Flag: The display cutout of this display is masked.
+ * @hide
+ */
+ public static final int FLAG_MASK_DISPLAY_CUTOUT = 1 << 11;
+
+ /**
* Touch attachment: Display does not receive touch.
*/
public static final int TOUCH_NONE = 0;
@@ -453,6 +459,9 @@
if ((flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
msg.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
}
+ if ((flags & FLAG_MASK_DISPLAY_CUTOUT) != 0) {
+ msg.append(", FLAG_MASK_DISPLAY_CUTOUT");
+ }
return msg.toString();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ddd8855..cc5a827 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -151,6 +151,8 @@
// Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
+ private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
+
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
@@ -243,6 +245,15 @@
// device).
private Point mStableDisplaySize = new Point();
+ // Whether the system has finished booting or not.
+ private boolean mSystemReady;
+
+ // The top inset of the default display.
+ // This gets persisted so that the boot animation knows how to transition from the display's
+ // full size to the size configured by the user. Right now we only persist and animate the top
+ // inset, but theoretically we could do it for all of them.
+ private int mDefaultDisplayTopInset;
+
// Viewports of the default display and the display that should receive touch
// input from an external source. Used by the input system.
private final DisplayViewport mDefaultViewport = new DisplayViewport();
@@ -301,6 +312,7 @@
Resources resources = mContext.getResources();
mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
+ mDefaultDisplayTopInset = SystemProperties.getInt(PROP_DEFAULT_DISPLAY_TOP_INSET, -1);
float[] lux = getFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_minimumBrightnessCurveLux));
float[] nits = getFloatArray(resources.obtainTypedArray(
@@ -311,6 +323,8 @@
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
mCurrentUserId = UserHandle.USER_SYSTEM;
+
+ mSystemReady = false;
}
public void setupSchedulerPolicies() {
@@ -400,6 +414,10 @@
synchronized (mSyncRoot) {
mSafeMode = safeMode;
mOnlyCore = onlyCore;
+ mSystemReady = true;
+ // Just in case the top inset changed before the system was ready. At this point, any
+ // relevant configuration should be in place.
+ recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
}
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -457,7 +475,7 @@
LogicalDisplay display = mLogicalDisplays.get(displayId);
if (display != null) {
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
- sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ handleLogicalDisplayChanged(displayId, display);
scheduleTraversalLocked(false);
}
}
@@ -938,6 +956,13 @@
scheduleTraversalLocked(false);
}
+ private void handleLogicalDisplayChanged(int displayId, @NonNull LogicalDisplay display) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ recordTopInsetLocked(display);
+ }
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ }
+
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
@@ -991,6 +1016,7 @@
configureColorModeLocked(display, device);
if (isDefault) {
recordStableDisplayStatsIfNeededLocked(display);
+ recordTopInsetLocked(display);
}
mLogicalDisplays.put(displayId, display);
@@ -1039,6 +1065,21 @@
}
}
+ private void recordTopInsetLocked(@Nullable LogicalDisplay d) {
+ // We must only persist the inset after boot has completed, otherwise we will end up
+ // overwriting the persisted value before the masking flag has been loaded from the
+ // resource overlay.
+ if (!mSystemReady || d == null) {
+ return;
+ }
+ int topInset = d.getInsets().top;
+ if (topInset == mDefaultDisplayTopInset) {
+ return;
+ }
+ mDefaultDisplayTopInset = topInset;
+ SystemProperties.set(PROP_DEFAULT_DISPLAY_TOP_INSET, Integer.toString(topInset));
+ }
+
private void setStableDisplaySizeLocked(int width, int height) {
mStableDisplaySize = new Point(width, height);
try {
@@ -1118,7 +1159,7 @@
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
changed = true;
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
- sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ handleLogicalDisplayChanged(displayId, display);
changed = true;
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 21ae048..16d82df 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -402,6 +402,10 @@
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
+ if (res.getBoolean(
+ com.android.internal.R.bool.config_maskMainBuiltInDisplayCutout)) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
+ }
mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
mInfo.width, mInfo.height);
mInfo.type = Display.TYPE_BUILT_IN;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 23ee56b..5b7c520 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -18,11 +18,14 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemProperties;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.server.wm.utils.InsetUtils;
+
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
@@ -55,6 +58,8 @@
* </p>
*/
final class LogicalDisplay {
+ private static final String PROP_MASKING_INSET_TOP = "persist.sys.displayinset.top";
+
private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
// The layer stack we use when the display has been blanked to prevent any
@@ -251,14 +256,18 @@
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
}
+ Rect maskingInsets = getMaskingInsets(deviceInfo);
+ int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right;
+ int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom;
+
mBaseDisplayInfo.type = deviceInfo.type;
mBaseDisplayInfo.address = deviceInfo.address;
mBaseDisplayInfo.name = deviceInfo.name;
mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId;
- mBaseDisplayInfo.appWidth = deviceInfo.width;
- mBaseDisplayInfo.appHeight = deviceInfo.height;
- mBaseDisplayInfo.logicalWidth = deviceInfo.width;
- mBaseDisplayInfo.logicalHeight = deviceInfo.height;
+ mBaseDisplayInfo.appWidth = maskedWidth;
+ mBaseDisplayInfo.appHeight = maskedHeight;
+ mBaseDisplayInfo.logicalWidth = maskedWidth;
+ mBaseDisplayInfo.logicalHeight = maskedHeight;
mBaseDisplayInfo.rotation = Surface.ROTATION_0;
mBaseDisplayInfo.modeId = deviceInfo.modeId;
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
@@ -275,13 +284,15 @@
mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
mBaseDisplayInfo.state = deviceInfo.state;
- mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
- mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
- mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
- mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
+ mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth;
+ mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight;
+ mBaseDisplayInfo.largestNominalAppWidth = maskedWidth;
+ mBaseDisplayInfo.largestNominalAppHeight = maskedHeight;
mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
- mBaseDisplayInfo.displayCutout = deviceInfo.displayCutout;
+ boolean maskCutout =
+ (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
+ mBaseDisplayInfo.displayCutout = maskCutout ? null : deviceInfo.displayCutout;
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo = null;
@@ -289,6 +300,29 @@
}
/**
+ * Return the insets currently applied to the display.
+ *
+ * Note that the base DisplayInfo already takes these insets into account, so if you want to
+ * find out the <b>true</b> size of the display, you need to add them back to the logical
+ * dimensions.
+ */
+ public Rect getInsets() {
+ return getMaskingInsets(mPrimaryDisplayDeviceInfo);
+ }
+
+ /**
+ * Returns insets in ROTATION_0 for areas that are masked.
+ */
+ private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) {
+ boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
+ if (maskCutout && deviceInfo.displayCutout != null) {
+ return deviceInfo.displayCutout.getSafeInsets();
+ } else {
+ return new Rect();
+ }
+ }
+
+ /**
* Applies the layer stack and transformation to the given display device
* so that it shows the contents of this logical display.
*
@@ -349,6 +383,12 @@
int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
+ Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
+ InsetUtils.rotateInsets(maskingInsets, orientation);
+ // Don't consider the masked area as available when calculating the scaling below.
+ physWidth -= maskingInsets.left + maskingInsets.right;
+ physHeight -= maskingInsets.top + maskingInsets.bottom;
+
// Determine whether the width or height is more constrained to be scaled.
// physWidth / displayInfo.logicalWidth => letter box
// or physHeight / displayInfo.logicalHeight => pillar box
@@ -375,6 +415,9 @@
mTempDisplayRect.set(displayRectLeft, displayRectTop,
displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
+ // Now add back the offset for the masked area.
+ mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);
+
mTempDisplayRect.left += mDisplayOffsetX;
mTempDisplayRect.right += mDisplayOffsetX;
mTempDisplayRect.top += mDisplayOffsetY;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 60e9eaa..e7459a4 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -945,7 +945,13 @@
@Override
public long getIfaceStats(String iface, int type) {
- return nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
+ // eBPF code doesn't provide per-interface TCP counters. Use xt_qtaguid for now.
+ // TODO: delete getMobileTcp(Rx|Tx)Packets entirely. See b/110443385 .
+ if (type == TYPE_TCP_TX_PACKETS || type == TYPE_TCP_RX_PACKETS) {
+ return nativeGetIfaceStat(iface, type, false);
+ } else {
+ return nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index c0fbfbb..18f4bc7 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -150,6 +150,7 @@
try {
provider.onConnected();
} catch (RemoteException e) {
+ Slog.e(TAG, "can't connect to service " + info, e);
// we tried
}
if (mCallback != null) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1284468..c6e71e5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2122,6 +2122,10 @@
enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
mRankingHelper.setEnabled(pkg, uid, enabled);
+ mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setPackageName(pkg)
+ .setSubtype(enabled ? 1 : 0));
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (!enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 6760875..b016faf 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -36,7 +36,8 @@
public class ZenLog {
private static final String TAG = "ZenLog";
- private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+ // the ZenLog is *very* verbose, so be careful about setting this to true
+ private static final boolean DEBUG = false;
private static final int SIZE = Build.IS_DEBUGGABLE ? 100 : 20;
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 63c0baf..b080a73 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -19,7 +19,6 @@
import android.content.ComponentName;
import android.net.Uri;
import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
@@ -27,6 +26,8 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.PrintWriter;
import java.util.Objects;
@@ -36,7 +37,9 @@
private final ZenModeHelper mHelper;
private final ConditionProviders mConditionProviders;
- private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
+
+ @VisibleForTesting
+ protected final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
private boolean mFirstEvaluation = true;
@@ -59,7 +62,8 @@
pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions);
}
- public void evaluateConfig(ZenModeConfig config, boolean processSubscriptions) {
+ public void evaluateConfig(ZenModeConfig config, ComponentName trigger,
+ boolean processSubscriptions) {
if (config == null) return;
if (config.manualRule != null && config.manualRule.condition != null
&& !config.manualRule.isTrueOrUnknown()) {
@@ -67,9 +71,9 @@
config.manualRule = null;
}
final ArraySet<Uri> current = new ArraySet<>();
- evaluateRule(config.manualRule, current, processSubscriptions);
+ evaluateRule(config.manualRule, current, null, processSubscriptions);
for (ZenRule automaticRule : config.automaticRules.values()) {
- evaluateRule(automaticRule, current, processSubscriptions);
+ evaluateRule(automaticRule, current, trigger, processSubscriptions);
updateSnoozing(automaticRule);
}
@@ -102,7 +106,7 @@
@Override
public void onServiceAdded(ComponentName component) {
if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
- mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
+ mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded");
}
@Override
@@ -110,17 +114,22 @@
if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
ZenModeConfig config = mHelper.getConfig();
if (config == null) return;
+ ComponentName trigger = null;
boolean updated = updateCondition(id, condition, config.manualRule);
for (ZenRule automaticRule : config.automaticRules.values()) {
updated |= updateCondition(id, condition, automaticRule);
updated |= updateSnoozing(automaticRule);
+ if (updated) {
+ trigger = automaticRule.component;
+ }
}
if (updated) {
- mHelper.setConfig(config, "conditionChanged");
+ mHelper.setConfig(config, trigger, "conditionChanged");
}
}
- private void evaluateRule(ZenRule rule, ArraySet<Uri> current, boolean processSubscriptions) {
+ private void evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger,
+ boolean processSubscriptions) {
if (rule == null || rule.conditionId == null) return;
final Uri id = rule.conditionId;
boolean isSystemCondition = false;
@@ -146,7 +155,9 @@
if (current != null) {
current.add(id);
}
- if (processSubscriptions) {
+ if (processSubscriptions && ((trigger != null && trigger.equals(rule.component))
+ || isSystemCondition)) {
+ if (DEBUG) Log.d(TAG, "Subscribing to " + rule.component);
if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
synchronized (mSubscriptions) {
mSubscriptions.put(rule.conditionId, rule.component);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 669d556..0c42f8a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -102,7 +102,7 @@
private final ZenModeFiltering mFiltering;
protected final RingerModeDelegate mRingerModeDelegate = new
RingerModeDelegate();
- private final ZenModeConditions mConditions;
+ @VisibleForTesting protected final ZenModeConditions mConditions;
private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
private final Metrics mMetrics = new Metrics();
private final ConditionProviders.Config mServiceConfig;
@@ -225,7 +225,7 @@
config.user = user;
}
synchronized (mConfig) {
- setConfigLocked(config, reason);
+ setConfigLocked(config, null, reason);
}
cleanUpZenRules();
}
@@ -312,7 +312,7 @@
ZenRule rule = new ZenRule();
populateZenRule(automaticZenRule, rule, true);
newConfig.automaticRules.put(rule.id, rule);
- if (setConfigLocked(newConfig, reason, true)) {
+ if (setConfigLocked(newConfig, reason, rule.component, true)) {
return rule.id;
} else {
throw new AndroidRuntimeException("Could not create rule");
@@ -342,7 +342,7 @@
}
populateZenRule(automaticZenRule, rule, false);
newConfig.automaticRules.put(ruleId, rule);
- return setConfigLocked(newConfig, reason, true);
+ return setConfigLocked(newConfig, reason, rule.component, true);
}
}
@@ -360,7 +360,7 @@
throw new SecurityException(
"Cannot delete rules not owned by your condition provider");
}
- return setConfigLocked(newConfig, reason, true);
+ return setConfigLocked(newConfig, reason, null, true);
}
}
@@ -376,7 +376,7 @@
newConfig.automaticRules.removeAt(i);
}
}
- return setConfigLocked(newConfig, reason, true);
+ return setConfigLocked(newConfig, reason, null, true);
}
}
@@ -537,7 +537,7 @@
newRule.enabler = caller;
newConfig.manualRule = newRule;
}
- setConfigLocked(newConfig, reason, setRingerMode);
+ setConfigLocked(newConfig, reason, null, setRingerMode);
}
}
@@ -644,7 +644,7 @@
}
if (DEBUG) Log.d(TAG, reason);
synchronized (mConfig) {
- setConfigLocked(config, reason);
+ setConfigLocked(config, null, reason);
}
}
}
@@ -673,7 +673,7 @@
synchronized (mConfig) {
final ZenModeConfig newConfig = mConfig.copy();
newConfig.applyNotificationPolicy(policy);
- setConfigLocked(newConfig, "setNotificationPolicy");
+ setConfigLocked(newConfig, null, "setNotificationPolicy");
}
}
@@ -697,7 +697,7 @@
}
}
}
- setConfigLocked(newConfig, "cleanUpZenRules");
+ setConfigLocked(newConfig, null, "cleanUpZenRules");
}
}
@@ -710,17 +710,19 @@
}
}
- public boolean setConfigLocked(ZenModeConfig config, String reason) {
- return setConfigLocked(config, reason, true /*setRingerMode*/);
+ public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent,
+ String reason) {
+ return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/);
}
- public void setConfig(ZenModeConfig config, String reason) {
+ public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason) {
synchronized (mConfig) {
- setConfigLocked(config, reason);
+ setConfigLocked(config, triggeringComponent, reason);
}
}
- private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
+ private boolean setConfigLocked(ZenModeConfig config, String reason,
+ ComponentName triggeringComponent, boolean setRingerMode) {
final long identity = Binder.clearCallingIdentity();
try {
if (config == null || !config.isValid()) {
@@ -733,7 +735,8 @@
if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
return true;
}
- mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
+ // may modify config
+ mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
mConfigs.put(config.user, config);
if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
ZenLog.traceConfig(reason, mConfig, config);
@@ -746,7 +749,7 @@
dispatchOnPolicyChanged();
}
mConfig = config;
- mHandler.postApplyConfig(config, reason, setRingerMode);
+ mHandler.postApplyConfig(config, reason, triggeringComponent, setRingerMode);
return true;
} catch (SecurityException e) {
Log.wtf(TAG, "Invalid rule in config", e);
@@ -756,13 +759,14 @@
}
}
- private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+ private void applyConfig(ZenModeConfig config, String reason,
+ ComponentName triggeringComponent, boolean setRingerMode) {
final String val = Integer.toString(config.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
if (!evaluateZenMode(reason, setRingerMode)) {
applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
}
- mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+ mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
}
private int getZenModeSetting() {
@@ -1260,13 +1264,16 @@
private final class ConfigMessageData {
public final ZenModeConfig config;
+ public ComponentName triggeringComponent;
public final String reason;
public final boolean setRingerMode;
- ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
+ ConfigMessageData(ZenModeConfig config, String reason,
+ ComponentName triggeringComponent, boolean setRingerMode) {
this.config = config;
this.reason = reason;
this.setRingerMode = setRingerMode;
+ this.triggeringComponent = triggeringComponent;
}
}
@@ -1286,9 +1293,10 @@
sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
}
- private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+ private void postApplyConfig(ZenModeConfig config, String reason,
+ ComponentName triggeringComponent, boolean setRingerMode) {
sendMessage(obtainMessage(MSG_APPLY_CONFIG,
- new ConfigMessageData(config, reason, setRingerMode)));
+ new ConfigMessageData(config, reason, triggeringComponent, setRingerMode)));
}
@Override
@@ -1303,7 +1311,7 @@
case MSG_APPLY_CONFIG:
ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
applyConfig(applyConfigData.config, applyConfigData.reason,
- applyConfigData.setRingerMode);
+ applyConfigData.triggeringComponent, applyConfigData.setRingerMode);
}
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index f082271..c738701 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -22,11 +22,14 @@
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -34,6 +37,7 @@
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
@@ -269,13 +273,30 @@
@Override
public void onBootPhase(int phase) {
- if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY && mInitCompleteSignal != null) {
ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
"Wait for OverlayManagerService init");
mInitCompleteSignal = null;
}
}
+ public void updateSystemUiContext() {
+ if (mInitCompleteSignal != null) {
+ ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
+ "Wait for OverlayManagerService init");
+ mInitCompleteSignal = null;
+ }
+
+ final ApplicationInfo ai;
+ try {
+ ai = mPackageManager.mPackageManager.getApplicationInfo("android",
+ GET_SHARED_LIBRARY_FILES, UserHandle.USER_SYSTEM);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai);
+ }
+
private void initIfNeeded() {
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index cf49d2a..95c70d5 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,6 +34,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
@@ -289,7 +290,8 @@
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
- profileName, dexMetadataPath, getReasonName(compilationReason));
+ profileName, dexMetadataPath,
+ getAugmentedReasonName(compilationReason, dexMetadataPath != null));
if (packageStats != null) {
long endTime = System.currentTimeMillis();
@@ -302,6 +304,12 @@
}
}
+ private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) {
+ String annotation = useDexMetadata
+ ? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : "";
+ return getReasonName(compilationReason) + annotation;
+ }
+
/**
* Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}.
*
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 29047e7..62c49e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12344,7 +12344,8 @@
if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
}
- mPermissionManager.removeAllPermissions(pkg, chatty);
+ final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
+ mPermissionManager.removeAllPermissions(pkg, allPackageNames, mPermissionCallback, chatty);
N = pkg.instrumentation.size();
r = null;
@@ -21952,9 +21953,6 @@
//TODO: b/111402650
private void disableSkuSpecificApps() {
- if (!mIsUpgrade && !mFirstBoot) {
- return;
- }
String apkList[] = mContext.getResources().getStringArray(
R.array.config_disableApksUnlessMatchedSku_apk_list);
String skuArray[] = mContext.getResources().getStringArray(
@@ -21968,7 +21966,9 @@
}
for (String packageName : apkList) {
setSystemAppHiddenUntilInstalled(packageName, true);
- setSystemAppInstallState(packageName, false, ActivityManager.getCurrentUser());
+ for (UserInfo user : sUserManager.getUsers(false)) {
+ setSystemAppInstallState(packageName, false, user.id);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 0ba7822..21daa39 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -519,6 +519,11 @@
private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
private static final int TRON_COMPILATION_REASON_SHARED = 8;
+ private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA = 9;
+
+ // The annotation to add as a suffix to the compilation reason when dexopt was
+ // performed with dex metadata.
+ public static final String DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION = "-dm";
/**
* Convert the compilation reason to an int suitable to be logged to TRON.
@@ -534,6 +539,10 @@
case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
case "shared" : return TRON_COMPILATION_REASON_SHARED;
+ // This is a special marker for dex metadata installation that does not
+ // have an equivalent as a system property.
+ case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+ return TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA;
default: return TRON_COMPILATION_REASON_UNKNOWN;
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index a042fed..c3f23a8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -115,7 +115,11 @@
*/
public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
- public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
+ public abstract void removeAllPermissions(
+ @NonNull PackageParser.Package pkg,
+ @NonNull List<String> allPackageNames,
+ @Nullable PermissionCallback permissionCallback,
+ boolean chatty);
public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async,
int callingUid, @Nullable PermissionCallback callback);
public abstract void removeDynamicPermission(@NonNull String permName, int callingUid,
@@ -189,4 +193,4 @@
/** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index c51a724..02c9049 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -30,6 +30,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
@@ -37,6 +38,7 @@
import android.content.pm.PermissionInfo;
import android.content.pm.PackageParser.Package;
import android.metrics.LogMaker;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -455,8 +457,9 @@
" to " + newPermissionGroupName);
try {
- revokeRuntimePermission(permissionName, packageName, false,
- Process.SYSTEM_UID, userId, permissionCallback);
+ revokeRuntimePermission(permissionName, packageName,
+ mSettings.getPermission(permissionName), false,
+ Process.SYSTEM_UID, userId, permissionCallback, false);
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Could not revoke " + permissionName + " from "
+ packageName, e);
@@ -549,9 +552,59 @@
}
- private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
+ private void revokeAllPermissions(
+ @NonNull List<BasePermission> bps,
+ @NonNull List<String> allPackageNames,
+ @Nullable PermissionCallback permissionCallback) {
+ AsyncTask.execute(() -> {
+ final int numRemovedPermissions = bps.size();
+ for (int permissionNum = 0; permissionNum < numRemovedPermissions; permissionNum++) {
+ final int[] userIds = mUserManagerInt.getUserIds();
+ final int numUserIds = userIds.length;
+
+ final int numPackages = allPackageNames.size();
+ for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+ final String packageName = allPackageNames.get(packageNum);
+ final ApplicationInfo applicationInfo = mPackageManagerInt.getApplicationInfo(
+ packageName, 0, Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
+ if (applicationInfo != null
+ && applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ continue;
+ }
+ for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
+ final int userId = userIds[userIdNum];
+ final String permissionName = bps.get(permissionNum).getName();
+ if (checkPermission(permissionName, packageName, UserHandle.USER_SYSTEM,
+ userId) == PackageManager.PERMISSION_GRANTED) {
+ try {
+ revokeRuntimePermission(
+ permissionName,
+ packageName,
+ bps.get(permissionNum),
+ false,
+ Process.SYSTEM_UID,
+ userId,
+ permissionCallback,
+ true);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Could not revoke " + permissionName + " from "
+ + packageName, e);
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ private void removeAllPermissions(
+ @NonNull PackageParser.Package pkg,
+ @NonNull List<String> allPackageNames,
+ @Nullable PermissionCallback permissionCallback,
+ boolean chatty) {
synchronized (mLock) {
int N = pkg.permissions.size();
+ List<BasePermission> bps = new ArrayList<BasePermission>(N);
StringBuilder r = null;
for (int i=0; i<N; i++) {
PackageParser.Permission p = pkg.permissions.get(i);
@@ -560,6 +613,9 @@
bp = mSettings.mPermissionTrees.get(p.info.name);
}
if (bp != null && bp.isPermission(p)) {
+ if ((p.info.getProtection() & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
+ bps.add(bp);
+ }
bp.setPermission(null);
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -578,6 +634,7 @@
}
}
}
+ revokeAllPermissions(bps, allPackageNames, permissionCallback);
if (r != null) {
if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
}
@@ -1490,9 +1547,10 @@
}
}
-
- private void revokeRuntimePermission(String permName, String packageName,
- boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) {
+
+ private void revokeRuntimePermission(String permName, String packageName, BasePermission bp,
+ boolean overridePolicy, int callingUid, int userId, PermissionCallback callback,
+ boolean permissionRemoved) {
if (!mUserManagerInt.exists(userId)) {
Log.e(TAG, "No such user:" + userId);
return;
@@ -1517,7 +1575,7 @@
if (mPackageManagerInt.filterAppAccess(pkg, Binder.getCallingUid(), userId)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final BasePermission bp = mSettings.getPermissionLocked(permName);
+
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
@@ -2073,8 +2131,10 @@
PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
}
@Override
- public void removeAllPermissions(Package pkg, boolean chatty) {
- PermissionManagerService.this.removeAllPermissions(pkg, chatty);
+ public void removeAllPermissions(Package pkg, List<String> allPackageNames,
+ PermissionCallback permissionCallback, boolean chatty) {
+ PermissionManagerService.this.removeAllPermissions(
+ pkg, allPackageNames, permissionCallback, chatty);
}
@Override
public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid,
@@ -2110,7 +2170,8 @@
boolean overridePolicy, int callingUid, int userId,
PermissionCallback callback) {
PermissionManagerService.this.revokeRuntimePermission(permName, packageName,
- overridePolicy, callingUid, userId, callback);
+ mSettings.getPermission(permName), overridePolicy, callingUid, userId,
+ callback, false);
}
@Override
public void updatePermissions(String packageName, Package pkg, boolean replaceGrant,
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index eca6f9f..14c985c 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -196,7 +196,7 @@
}
protected boolean skipAnimation() {
- return false;
+ return !mWin.isDrawnLw();
}
private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dfb6179..9a741bc 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -76,6 +76,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_BAR_EXPANDED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
@@ -4397,17 +4398,9 @@
if (isKeyguardShowingAndNotOccluded()) {
// don't launch home if keyguard showing
return;
- } else if (mKeyguardOccluded && mKeyguardDelegate.isShowing()) {
- mKeyguardDelegate.dismiss(new KeyguardDismissCallback() {
- @Override
- public void onDismissSucceeded() throws RemoteException {
- mHandler.post(() -> {
- startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
- });
- }
- }, null /* message */);
- return;
- } else if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) {
+ }
+
+ if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
// before launching home
mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
@@ -4692,8 +4685,7 @@
navTranslucent &= areTranslucentBarsAllowed();
}
boolean statusBarExpandedNotKeyguard = !isKeyguardShowing && mStatusBar != null
- && mStatusBar.getAttrs().height == MATCH_PARENT
- && mStatusBar.getAttrs().width == MATCH_PARENT;
+ && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_STATUS_BAR_EXPANDED) != 0;
// When the navigation bar isn't visible, we put up a fake input window to catch all
// touch events. This way we can detect when the user presses anywhere to bring back the
@@ -5696,7 +5688,7 @@
}
// Take note if a window wants to acquire a sleep token.
- if (win.isVisibleLw() && (attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0
+ if ((attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0
&& win.canAcquireSleepToken()) {
mWindowSleepTokenNeeded = true;
}
@@ -5752,9 +5744,8 @@
mStatusBarController.setShowTransparent(true /* transparent */);
}
- WindowManager.LayoutParams statusBarAttrs = mStatusBar.getAttrs();
- boolean statusBarExpanded = statusBarAttrs.height == MATCH_PARENT
- && statusBarAttrs.width == MATCH_PARENT;
+ boolean statusBarExpanded =
+ (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_STATUS_BAR_EXPANDED) != 0;
boolean topAppHidesStatusBar = topAppHidesStatusBar();
if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
|| statusBarExpanded) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 4413666..f9f4bbf 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -46,7 +46,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
@@ -60,7 +59,6 @@
import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
@@ -431,13 +429,20 @@
for (int i = 0; i < userInfos.size(); i++) {
UserInfo info = userInfos.get(i);
- if (info == null || info.partial || !info.isEnabled() || info.guestToRemove
- || !info.supportsSwitchToByUser()) {
+ if (info == null || info.partial || !info.isEnabled() || info.guestToRemove) {
continue;
}
int id = info.id;
boolean secure = mLockPatternUtils.isSecure(id);
+
+ if (!info.supportsSwitchToByUser()) {
+ if (info.isManagedProfile() && !secure) {
+ setDeviceLockedForUser(id, false);
+ }
+ continue;
+ }
+
boolean trusted = aggregateIsTrusted(id);
boolean showingKeyguard = true;
boolean fingerprintAuthenticated = false;
@@ -992,7 +997,8 @@
enforceReportPermission();
final long identity = Binder.clearCallingIdentity();
try {
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+ && mLockPatternUtils.isSecure(userId)) {
synchronized (mDeviceLockedForUser) {
mDeviceLockedForUser.put(userId, locked);
}
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index b2a12be..86f328d 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -31,11 +31,13 @@
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.Choreographer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -112,6 +114,7 @@
private final Interpolator mFastOutSlowInInterpolator;
private boolean mFinishAnimationAfterTransition = false;
private final AnimationHandler mAnimationHandler;
+ private Choreographer mChoreographer;
private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
@@ -123,6 +126,12 @@
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
mAnimationHandler = animationHandler;
+ if (animationHandler != null) {
+ // If an animation handler is provided, then ensure that it runs on the sf vsync tick
+ handler.runWithScissors(() -> mChoreographer = Choreographer.getSfInstance(),
+ 0 /* timeout */);
+ animationHandler.setProvider(new SfVsyncFrameCallbackProvider(mChoreographer));
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2887e5ef..2941e93 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1775,8 +1775,9 @@
final int newDensity = mDisplayInfo.logicalDensityDpi;
final DisplayCutout newCutout = mDisplayInfo.displayCutout;
- final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
- || mInitialDisplayHeight != newHeight
+ final boolean sizeChanged = mInitialDisplayWidth != newWidth
+ || mInitialDisplayHeight != newHeight;
+ final boolean displayMetricsChanged = sizeChanged
|| mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi
|| !Objects.equals(mInitialDisplayCutout, newCutout);
@@ -1798,6 +1799,10 @@
mInitialDisplayCutout = newCutout;
mService.reconfigureDisplayLocked(this);
}
+
+ if (isDefaultDisplay && sizeChanged) {
+ mService.mH.post(mService.mAmInternal::notifyDefaultDisplaySizeChanged);
+ }
}
/** Sets the maximum width the screen resolution can be */
diff --git a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
index f25ec5c..efb43a6 100644
--- a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
@@ -21,6 +21,7 @@
import android.graphics.Matrix;
import android.view.DisplayInfo;
+import android.view.Surface.Rotation;
import com.android.server.wm.utils.CoordinateTransforms;
@@ -65,6 +66,16 @@
}
/**
+ * Returns the rotation of the display before it started rotating.
+ *
+ * @return the old rotation of the display
+ */
+ @Rotation
+ public int getOldRotation() {
+ return mOldRotation;
+ }
+
+ /**
* Removes the transform to the window token's surface that undoes the effect of the global
* display rotation.
*
@@ -75,12 +86,14 @@
public void finish(WindowToken token, WindowState win) {
mTransform.reset();
token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9);
- token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl,
- win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
- win.getFrameNumber());
- win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl,
- win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
- win.getFrameNumber());
+ if (win.mWinAnimator.mSurfaceController != null) {
+ token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl,
+ win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
+ win.getFrameNumber());
+ win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl,
+ win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
+ win.getFrameNumber());
+ }
}
public void dump(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index fa8a5c6..755a571 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -37,6 +37,7 @@
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -268,6 +269,12 @@
.setSecure(isSecure)
.build();
+ // In case display bounds change, screenshot buffer and surface may mismatch so set a
+ // scaling mode.
+ Transaction t2 = new Transaction();
+ t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
+ t2.apply(true /* sync */);
+
// capture a screenshot into the surface we just created
// TODO(multidisplay): we should use the proper display
final int displayId = SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8bc2246..8b4a2dd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1005,7 +1005,6 @@
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
final AnimationHandler animationHandler = new AnimationHandler();
- animationHandler.setProvider(new SfVsyncFrameCallbackProvider());
mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
AnimationThread.getHandler(), animationHandler);
@@ -6221,6 +6220,17 @@
}
/**
+ * Returns true if the callingUid has any window currently visible to the user.
+ */
+ public boolean isAnyWindowVisibleForUid(int callingUid) {
+ synchronized (mWindowMap) {
+ return mRoot.forAllWindows(w -> {
+ return w.getOwningUid() == callingUid && w.isVisible();
+ }, true /* traverseTopToBottom */);
+ }
+ }
+
+ /**
* Called when a task has been removed from the recent tasks list.
* <p>
* Note: This doesn't go through {@link TaskWindowContainerController} yet as the window
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 009f393..1ae680f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -681,6 +681,10 @@
void forceSeamlesslyRotateIfAllowed(int oldRotation, int rotation) {
if (mForceSeamlesslyRotate) {
+ if (mPendingForcedSeamlessRotate != null) {
+ oldRotation = mPendingForcedSeamlessRotate.getOldRotation();
+ }
+
mPendingForcedSeamlessRotate = new ForcedSeamlessRotator(
oldRotation, rotation, getDisplayInfo());
mPendingForcedSeamlessRotate.unrotate(this.mToken);
diff --git a/services/core/java/com/android/server/wm/utils/InsetUtils.java b/services/core/java/com/android/server/wm/utils/InsetUtils.java
index b4a998a..c8600dd 100644
--- a/services/core/java/com/android/server/wm/utils/InsetUtils.java
+++ b/services/core/java/com/android/server/wm/utils/InsetUtils.java
@@ -17,6 +17,7 @@
package com.android.server.wm.utils;
import android.graphics.Rect;
+import android.view.Surface;
/**
* Utility methods to handle insets represented as rects.
@@ -27,6 +28,32 @@
}
/**
+ * Transforms insets given in one rotation into insets in a different rotation.
+ *
+ * @param inOutInsets the insets to transform, is set to the transformed insets
+ * @param rotationDelta the delta between the new and old rotation.
+ * Must be one of Surface.ROTATION_0/90/180/270.
+ */
+ public static void rotateInsets(Rect inOutInsets, int rotationDelta) {
+ final Rect r = inOutInsets;
+ switch (rotationDelta) {
+ case Surface.ROTATION_0:
+ return;
+ case Surface.ROTATION_90:
+ r.set(r.top, r.right, r.bottom, r.left);
+ break;
+ case Surface.ROTATION_180:
+ r.set(r.right, r.bottom, r.left, r.top);
+ break;
+ case Surface.ROTATION_270:
+ r.set(r.bottom, r.left, r.top, r.right);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown rotation: " + rotationDelta);
+ }
+ }
+
+ /**
* Adds {@code insetsToAdd} to {@code inOutInsets}.
*/
public static void addInsets(Rect inOutInsets, Rect insetsToAdd) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b74a582..6ee7d49 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4572,10 +4572,12 @@
enforceFullCrossUsersPermission(userHandle);
synchronized (getLockObject()) {
if (!isCallerWithSystemUid()) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(
- null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+ // This API can be called by an active device admin or by keyguard code.
+ if (mContext.checkCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+ getActiveAdminForCallerLocked(
+ null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+ }
}
DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 82a2895..e917802 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,6 +29,7 @@
import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
+import android.hardware.display.DisplayManagerInternal;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -681,9 +682,17 @@
// Manages Overlay packages
traceBeginAndSlog("StartOverlayManagerService");
- mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
+ OverlayManagerService overlayManagerService = new OverlayManagerService(
+ mSystemContext, installer);
+ mSystemServiceManager.startService(overlayManagerService);
traceEnd();
+ if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
+ // DisplayManager needs the overlay immediately.
+ overlayManagerService.updateSystemUiContext();
+ LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
+ }
+
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
// Start sensor service in a separate thread. Completion should be checked
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index 1520859..8d056fc 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -53,6 +53,7 @@
import org.junit.runner.RunWith;
import org.junit.Test;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static com.android.server.am.ActivityManagerService.ANIMATE;
@@ -62,11 +63,13 @@
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
@@ -91,6 +94,7 @@
private ActivityManagerService mService;
private ActivityStarter mStarter;
private ActivityStartController mController;
+ private ActivityMetricsLogger mActivityMetricsLogger;
private static final int PRECONDITION_NO_CALLER_APP = 1;
private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
@@ -104,11 +108,17 @@
private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
+ private static final int FAKE_CALLING_UID = 666;
+ private static final int FAKE_REAL_CALLING_UID = 667;
+ private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
+
@Override
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
mController = mock(ActivityStartController.class);
+ mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
+ clearInvocations(mActivityMetricsLogger);
mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
mock(ActivityStartInterceptor.class));
}
@@ -471,4 +481,46 @@
assertTrue(stack.getAllTasks().isEmpty());
}
}
+
+ /**
+ * This test ensures that activity starts are not being logged when the logging is disabled.
+ */
+ @Test
+ public void testActivityStartsLogging_noLoggingWhenDisabled() {
+ doReturn(false).when(mService).isActivityStartsLoggingEnabled();
+ doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
+
+ ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
+ starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
+
+ // verify logging wasn't done
+ verify(mActivityMetricsLogger, never()).logActivityStart(any(), any(), any(), anyInt(),
+ any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyInt(), any(),
+ anyInt(), anyBoolean(), any(), anyBoolean());
+ }
+
+ /**
+ * This test ensures that activity starts are being logged when the logging is enabled.
+ */
+ @Test
+ public void testActivityStartsLogging_logsWhenEnabled() {
+ // note: conveniently this package doesn't have any activity visible
+ doReturn(true).when(mService).isActivityStartsLoggingEnabled();
+ doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
+
+ ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
+ .setCallingUid(FAKE_CALLING_UID)
+ .setRealCallingUid(FAKE_REAL_CALLING_UID)
+ .setCallingPackage(FAKE_CALLING_PACKAGE)
+ .setOriginatingPendingIntent(null);
+
+ starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
+
+ // verify the above activity start was logged
+ verify(mActivityMetricsLogger, times(1)).logActivityStart(any(), any(), any(),
+ eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
+ eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), anyInt(),
+ eq(ActivityBuilder.getDefaultComponent().getPackageName()), anyInt(), anyBoolean(),
+ any(), eq(false));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
index d0f0fe3..08bcc3d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
@@ -16,6 +16,11 @@
package com.android.server.wm.utils;
+import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+
import static junit.framework.Assert.assertEquals;
import android.graphics.Rect;
@@ -39,5 +44,29 @@
InsetUtils.addInsets(rect1, rect2);
assertEquals(new Rect(60, 80, 100, 120), rect1);
}
+
+ @Test
+ public void rotate() {
+ final Rect original = new Rect(1, 2, 3, 4);
+
+ assertEquals("rot0", original, rotateCopy(original, ROTATION_0));
+
+ final Rect rot90 = rotateCopy(original, ROTATION_90);
+ assertEquals("rot90", new Rect(2, 3, 4, 1), rot90);
+
+ final Rect rot180 = rotateCopy(original, ROTATION_180);
+ assertEquals("rot180", new Rect(3, 4, 1, 2), rot180);
+ assertEquals("rot90(rot90)=rot180", rotateCopy(rot90, ROTATION_90), rot180);
+
+ final Rect rot270 = rotateCopy(original, ROTATION_270);
+ assertEquals("rot270", new Rect(4, 1, 2, 3), rot270);
+ assertEquals("rot90(rot180)=rot270", rotateCopy(rot180, ROTATION_90), rot270);
+ }
+
+ private static Rect rotateCopy(Rect insets, int rotationDelta) {
+ final Rect copy = new Rect(insets);
+ InsetUtils.rotateInsets(copy, rotationDelta);
+ return copy;
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index afc1263..8222c38 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.content.ComponentName;
@@ -49,8 +50,10 @@
import android.media.AudioManagerInternal;
import android.media.VolumePolicy;
import android.media.AudioSystem;
+import android.net.Uri;
import android.provider.Settings;
import android.provider.Settings.Global;
+import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.test.suitebuilder.annotation.SmallTest;
@@ -61,6 +64,7 @@
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import android.util.Slog;
@@ -83,7 +87,7 @@
@TestableLooper.RunWithLooper
public class ZenModeHelperTest extends UiServiceTestCase {
- @Mock ConditionProviders mConditionProviders;
+ ConditionProviders mConditionProviders;
@Mock NotificationManager mNotificationManager;
@Mock private Resources mResources;
private TestableLooper mTestableLooper;
@@ -103,6 +107,9 @@
when(mResources.getString(R.string.zen_mode_default_events_name)).thenReturn("events");
when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
+ mConditionProviders = new ConditionProviders(mContext, new UserProfiles(),
+ AppGlobals.getPackageManager());
+ mConditionProviders.addSystemProvider(new CountdownConditionProvider());
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders));
}
@@ -116,7 +123,7 @@
mZenModeHelperSpy.writeXml(serializer, forBackup, version);
serializer.endDocument();
serializer.flush();
- mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml");
+ mZenModeHelperSpy.setConfig(new ZenModeConfig(), null, "writing xml");
return baos;
}
@@ -813,6 +820,30 @@
setupZenConfigMaintained();
}
+ @Test
+ public void testCountdownConditionSubscription() throws Exception {
+ ZenModeConfig config = new ZenModeConfig();
+ mZenModeHelperSpy.mConfig = config;
+ mZenModeHelperSpy.mConditions.evaluateConfig(mZenModeHelperSpy.mConfig, null, true);
+ assertEquals(0, mZenModeHelperSpy.mConditions.mSubscriptions.size());
+
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ Uri conditionId = ZenModeConfig.toCountdownConditionId(9000000, false);
+ mZenModeHelperSpy.mConfig.manualRule.conditionId = conditionId;
+ mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("android",
+ CountdownConditionProvider.class.getName());
+ mZenModeHelperSpy.mConfig.manualRule.condition = new Condition(conditionId, "", "", "", 0,
+ Condition.STATE_TRUE, Condition.FLAG_RELEVANT_NOW);
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ ZenModeConfig originalConfig = mZenModeHelperSpy.mConfig.copy();
+
+ mZenModeHelperSpy.mConditions.evaluateConfig(mZenModeHelperSpy.mConfig, null, true);
+
+ assertEquals(true, ZenModeConfig.isValidCountdownConditionId(conditionId));
+ assertEquals(originalConfig, mZenModeHelperSpy.mConfig);
+ assertEquals(1, mZenModeHelperSpy.mConditions.mSubscriptions.size());
+ }
+
private void setupZenConfig() {
mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 66c1a3c..17847ea 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -954,16 +954,15 @@
* for Hotspot 2.0 defined matching of AAA server certs per WFA HS2.0 spec, section 7.3.3.2,
* second paragraph.
*
- * From wpa_supplicant documentation:
- * Constraint for server domain name. If set, this FQDN is used as a suffix match requirement
+ * <p>From wpa_supplicant documentation:
+ * <p>Constraint for server domain name. If set, this FQDN is used as a suffix match requirement
* for the AAAserver certificate in SubjectAltName dNSName element(s). If a matching dNSName is
- * found, this constraint is met. If no dNSName values are present, this constraint is matched
- * against SubjectName CN using same suffix match comparison.
- * Suffix match here means that the host/domain name is compared one label at a time starting
+ * found, this constraint is met.
+ * <p>Suffix match here means that the host/domain name is compared one label at a time starting
* from the top-level domain and all the labels in domain_suffix_match shall be included in the
* certificate. The certificate may include additional sub-level labels in addition to the
* required labels.
- * For example, domain_suffix_match=example.com would match test.example.com but would not
+ * <p>For example, domain_suffix_match=example.com would match test.example.com but would not
* match test-example.com.
* @param domain The domain value
*/