diff options
145 files changed, 2884 insertions, 905 deletions
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 8ffe5bf59315..ed6c25dc49c3 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -302,6 +302,7 @@ status_t BootAnimation::readyToRun() { 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 @@ bool BootAnimation::playAnimation(const Animation& animation) if (mClockEnabled && mTimeIsAccurate && validClock(part)) { drawClock(animation.clockFont, part.clockPosX, part.clockPosY); } + handleViewport(frameDuration); eglSwapBuffers(mDisplay, mSurface); @@ -966,7 +968,7 @@ bool BootAnimation::playAnimation(const Animation& animation) 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 @@ bool BootAnimation::playAnimation(const Animation& animation) 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 56e131523bcb..b4699d884681 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -157,11 +157,15 @@ private: 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 be2e2faf3739..f0a0e88310f9 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -30,7 +30,6 @@ import android.content.res.Resources; 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 @@ public class AccessibilityServiceInfo implements Parcelable { * 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 @@ public class AccessibilityServiceInfo implements Parcelable { * 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 class AccessibilityServiceInfo implements Parcelable { 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 7f4ea1d0c532..cdcba9b0d91a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6377,6 +6377,10 @@ public class Activity extends ContextThemeWrapper } 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 @@ public class Activity extends ContextThemeWrapper 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 9b6764d96fb2..14cae95508e7 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -413,4 +413,9 @@ public abstract class ActivityManagerInternal { * @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 b2b85d442301..d526bccf90a9 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -960,14 +960,15 @@ public class ActivityOptions { } /** - * 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 9c516d26bb71..9e06e9faca02 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -147,6 +147,7 @@ import com.android.internal.os.RuntimeInit; 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 @@ public final class ActivityThread extends ClientTransactionHandler { } } + /** + * 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 68869c65d7c9..2d9fbf974397 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -125,10 +125,13 @@ public class ResourcesManager { } } + 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 @@ public class ResourcesManager { 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 @@ public class ResourcesManager { 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 @@ public class ResourcesManager { } 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 @@ public class ResourcesManager { 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 7bcc209c6500..eb8d8d37ae29 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3889,6 +3889,11 @@ public class DevicePolicyManager { /** * 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 2a451ff07672..bcd5f6c7497f 100644 --- a/core/java/android/app/admin/SystemUpdatePolicy.java +++ b/core/java/android/app/admin/SystemUpdatePolicy.java @@ -76,9 +76,7 @@ import java.util.stream.Collectors; * </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 d568662409d7..dd61f286c88e 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -41,18 +41,23 @@ import java.util.Arrays; 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 7ab3d8bdd857..5694ca860453 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 @@ public abstract class AppWidgetManagerInternal { * @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 925fa4a7c567..60ac1f08ba66 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -21,7 +21,6 @@ import android.annotation.SystemService; 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.graphics.drawable.AdaptiveIconDrawable; 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 @@ public class ShortcutManager { } /** - * 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 @@ public class ShortcutManager { /** * 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 @@ public class ShortcutManager { /** * 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 @@ public class ShortcutManager { * 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 @@ public class ShortcutManager { * @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 424da7602a58..25d98f7edf06 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -1757,7 +1757,8 @@ public final class SQLiteDatabase extends SQLiteClosable { 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 1bd44fa5c2c6..a984200c0920 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 @@ public class SQLiteQueryBuilder if (mWhereClause == null) { mWhereClause = new StringBuilder(inWhere.length() + 16); } - if (mWhereClause.length() == 0) { - mWhereClause.append('('); - } mWhereClause.append(inWhere); } @@ -119,9 +124,6 @@ public class SQLiteQueryBuilder if (mWhereClause == null) { mWhereClause = new StringBuilder(inWhere.length() + 16); } - if (mWhereClause.length() == 0) { - mWhereClause.append('('); - } DatabaseUtils.appendEscapedSQLString(mWhereClause, inWhere); } @@ -380,6 +382,11 @@ public class SQLiteQueryBuilder 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 @@ public class SQLiteQueryBuilder // 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 @@ public class SQLiteQueryBuilder 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 @@ public class SQLiteQueryBuilder 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 @@ public class SQLiteQueryBuilder } 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 9b18e9a12969..35584ae21869 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1255,7 +1255,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <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 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <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 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </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 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * 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 1275a852ee2b..caa99d5cb2a8 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -819,11 +819,11 @@ public abstract class CameraMetadata<TKey> { * 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 0b92b0cbef15..4a20468276d3 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -2530,7 +2530,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * 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 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> 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 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * 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 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * {@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 e007d282ad04..1e894e8a29c2 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2858,7 +2858,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * </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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * 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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * 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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { 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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { 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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * 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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * {@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 1b22911f0cdc..22dd4fc362ba 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -333,6 +333,14 @@ public class TrafficStats { /** * 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 91888949829f..68b6d722f345 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -628,7 +628,8 @@ public class Build { * 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 @@ public class Build { * 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 @@ public class Build { /** * 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 @@ public class Build { * 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 @@ public class Build { * 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 class Build { 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 @@ public class Build { * 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 @@ public class Build { * 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 @@ public class Build { * 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 @@ public class Build { * <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 b303e10fa64b..455d8edd4138 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -349,7 +349,7 @@ public final class Message implements Parcelable { } /** - * 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 d4d3dc838d91..7b3ea57ba0e9 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -65,11 +65,17 @@ public final class StatsLogEventWrapper implements Parcelable { 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 @@ public final class StatsLogEventWrapper implements Parcelable { 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 @@ public final class StatsLogEventWrapper implements Parcelable { } /** - * 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 d16390976d1f..8ed2605e9e8c 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -80,7 +80,7 @@ import java.util.List; * <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 6f6a9be5b909..1817972981e9 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10618,6 +10618,15 @@ public final class Settings { 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 521176797657..f8408bedd7bc 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -33,8 +33,13 @@ import java.util.ArrayList; 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 @@ import java.util.regex.Pattern; * <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 0257891e5f38..1695c1306824 100644 --- a/core/java/android/service/autofill/FillCallback.java +++ b/core/java/android/service/autofill/FillCallback.java @@ -21,8 +21,11 @@ import android.app.Activity; 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 b6c6bdc00bbe..5a7a83f19b0c 100644 --- a/core/java/android/service/notification/Condition.java +++ b/core/java/android/service/notification/Condition.java @@ -151,14 +151,14 @@ public final class Condition implements Parcelable { @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 f6749ee66bb4..1af2e73c95ce 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -244,11 +244,29 @@ public class ZenModeConfig implements Parcelable { .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 @@ public class ZenModeConfig implements Parcelable { @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 class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { @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 @@ public class ZenModeConfig implements Parcelable { 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 3afa3252c5a3..8a49c2859d1b 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1590,7 +1590,8 @@ public abstract class Layout { } 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 dc07494b15db..aa5ca3530621 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -23,32 +23,34 @@ import android.annotation.UnsupportedAppUsage; 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 @@ public class SparseArray<E> implements Cloneable { /** * 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 @@ public class SparseArray<E> implements Cloneable { /** * 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 496bc9ff5383..5f80d31651a8 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -325,6 +325,7 @@ public final class DisplayCutout { * * @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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { 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 3f7ab2aed4af..38dcdd30d843 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -33,9 +33,14 @@ import com.android.internal.util.Preconditions; 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 8b9b85651e7e..84a460119726 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1699,6 +1699,15 @@ public interface WindowManager extends ViewManager { 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 @@ public interface WindowManager extends ViewManager { @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 769ea3e1d2c4..b382a1863af3 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -628,7 +628,7 @@ public class AccessibilityRecord { } /** - * 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 7555ffff3e38..d21cb3e64b8c 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -77,11 +77,16 @@ import java.util.Objects; 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 @@ import sun.misc.Cleaner; * <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 @@ import sun.misc.Cleaner; * 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 @@ public final class AutofillManager { 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 @@ public final class AutofillManager { 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 @@ public final class AutofillManager { @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 0c34e3c16ac6..4d3bbe475920 100644 --- a/core/java/android/webkit/WebBackForwardList.java +++ b/core/java/android/webkit/WebBackForwardList.java @@ -57,7 +57,8 @@ public abstract class WebBackForwardList implements Cloneable, Serializable { /** * 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 74db039e015d..b9e704285f84 100644 --- a/core/java/android/webkit/WebHistoryItem.java +++ b/core/java/android/webkit/WebHistoryItem.java @@ -23,7 +23,7 @@ import android.graphics.Bitmap; /** * 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 @@ public abstract class WebHistoryItem implements Cloneable { * 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 @@ public abstract class WebHistoryItem implements Cloneable { /** * 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 66e079e26f1f..c30edd30361f 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -991,7 +991,9 @@ public abstract class WebSettings { * {@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 @@ public abstract class WebSettings { * * @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 5c5e9de77916..8f03b693e587 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -42,7 +42,6 @@ import android.os.Message; 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 @@ public class WebView extends AbsoluteLayout /** * 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 f686b6645655..bdd7a0900213 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -31,18 +31,25 @@ import java.lang.annotation.RetentionPolicy; 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 @@ 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. - * - * <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> + * 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 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 3956215b6f83..66ce0eeafc96 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -812,7 +812,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @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 398d08791b5c..4728124c17c5 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.UserHandle; 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 @@ import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; * 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 class IntentForwarderActivity extends Activity { 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 @@ public class IntentForwarderActivity extends Activity { 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 @@ public class IntentForwarderActivity extends Activity { + 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 @@ public class IntentForwarderActivity extends Activity { 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 class IntentForwarderActivity extends Activity { 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 @@ public class IntentForwarderActivity extends Activity { 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 94c3933c55f0..e6dc352e63af 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -4031,7 +4031,9 @@ public class BatteryStatsImpl extends BatteryStats { 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 64b1f241464b..0c8613b460f6 100644 --- a/core/java/com/android/internal/widget/MessagingLinearLayout.java +++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java @@ -111,14 +111,16 @@ public class MessagingLinearLayout extends ViewGroup { 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 @@ public class MessagingLinearLayout extends ViewGroup { } 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 24150a782d22..41e24d779362 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 c819de2ba43c..0085a1b7e190 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 000000000000..84e779d240d1 --- /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 000000000000..84e779d240d1 --- /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 000000000000..84e779d240d1 --- /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 969b6021689c..8f1c9320c762 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 471170bbe93b..73cb59e84644 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 9520d6d05960..4fd94a217207 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 483381660655..090f9afb551e 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -306,6 +306,7 @@ please see themes_device_defaults.xml. <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 cb5b93dd7df4..33832d4eb689 100644 --- a/core/res/res/values/themes_holo.xml +++ b/core/res/res/values/themes_holo.xml @@ -296,6 +296,7 @@ please see themes_device_defaults.xml. <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 @@ please see themes_device_defaults.xml. <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 43af1a3eb804..583b2cd91730 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -99,6 +99,7 @@ public class SettingsBackupTest { 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 6ee74cb9a742..fe45fe7d3aaf 100644 --- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java +++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java @@ -19,6 +19,7 @@ package android.view; 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 @@ public class DisplayCutoutTest { } @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 b18fa747557d..c165b6be525e 100644 --- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java @@ -16,46 +16,50 @@ package com.android.internal.app; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +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 android.util.Log; - +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.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; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(AndroidJUnit4.class) public class IntentForwarderActivityTest { + private static final ComponentName FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME = new ComponentName( "android", @@ -77,22 +81,26 @@ public class IntentForwarderActivityTest { 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 @@ public class IntentForwarderActivityTest { 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 @@ public class IntentForwarderActivityTest { } } - class TestInjector implements IntentForwarderActivity.Injector { + public class TestInjector implements IntentForwarderActivity.Injector { @Override public IPackageManager getIPackageManager() { @@ -292,5 +443,21 @@ public class IntentForwarderActivityTest { 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 2503381a501f..ef58c8f2bd16 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -1600,9 +1600,9 @@ public class Canvas extends BaseCanvas { * 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 419eb24e1cc1..953cef7d30ff 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -301,6 +301,9 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { 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 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { 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 1be8309bcf5a..f7993eff6b08 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -22,9 +22,9 @@ import android.annotation.RequiresPermission; 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 @@ public abstract class AttestationUtils { @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 @@ public abstract class AttestationUtils { } } 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 3643ca4a02f7..8a02a82194df 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 @@ package com.android.internal.location.gnssmetrics; 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 @@ public class GnssMetrics { = 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 @@ public class GnssMetrics { 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 76fc9e350ecc..d45acdfa627e 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -405,7 +405,7 @@ import java.util.Map; <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 a3c1fc6ff265..fd80edf839bc 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.File; 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 @@ public class ApplicationsState { 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 @@ public class ApplicationsState { 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 @@ public class ApplicationsState { 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 373247162563..1c50953bac12 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 @@ package com.android.settingslib.bluetooth; 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 @@ public class LocalBluetoothManager { 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 class LocalBluetoothManager { } 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 988060eac64d..e5d97c9b4a7b 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.AttributeSet; 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 class DreamBackend { } 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 61f7fe8dc019..bf4374acf6e6 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 @@ public interface QSTile { boolean isAvailable(); void setTileSpec(String tileSpec); - void clearState(); + @Deprecated default void clearState() {} void refreshState(); void addCallback(Callback callback); diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml index baaf699c278a..d72021e27e0b 100644 --- a/packages/SystemUI/res/layout/navigation_layout.xml +++ b/packages/SystemUI/res/layout/navigation_layout.xml @@ -18,14 +18,16 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:layout_marginStart="@dimen/rounded_corner_content_padding" + android:layout_marginEnd="@dimen/rounded_corner_content_padding" + android:paddingStart="@dimen/nav_content_padding" + android:paddingEnd="@dimen/nav_content_padding"> <com.android.systemui.statusbar.phone.NearestTouchFrame android:id="@+id/nav_buttons" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingStart="@dimen/rounded_corner_content_padding" - android:paddingEnd="@dimen/rounded_corner_content_padding" android:clipChildren="false" android:clipToPadding="false"> @@ -34,8 +36,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:paddingStart="@dimen/nav_content_padding" - android:paddingEnd="@dimen/nav_content_padding" android:clipToPadding="false" android:clipChildren="false" /> @@ -46,8 +46,6 @@ android:layout_gravity="center" android:gravity="center" android:orientation="horizontal" - android:paddingStart="@dimen/nav_content_padding" - android:paddingEnd="@dimen/nav_content_padding" android:clipToPadding="false" android:clipChildren="false" /> diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml index 6d5b77885a09..24a0c71f3bad 100644 --- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml +++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml @@ -18,14 +18,16 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/rounded_corner_content_padding" + android:layout_marginBottom="@dimen/rounded_corner_content_padding" + android:paddingTop="@dimen/nav_content_padding" + android:paddingBottom="@dimen/nav_content_padding"> <com.android.systemui.statusbar.phone.NearestTouchFrame android:id="@+id/nav_buttons" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingTop="@dimen/rounded_corner_content_padding" - android:paddingBottom="@dimen/rounded_corner_content_padding" android:clipChildren="false" android:clipToPadding="false"> @@ -34,10 +36,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:paddingTop="@dimen/nav_content_padding" - android:paddingBottom="@dimen/nav_content_padding" - android:clipChildren="false" - android:clipToPadding="false" /> + android:clipToPadding="false" + android:clipChildren="false" /> <com.android.systemui.statusbar.phone.ReverseLinearLayout android:id="@+id/center_group" @@ -45,10 +45,8 @@ android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" - android:paddingTop="@dimen/nav_content_padding" - android:paddingBottom="@dimen/nav_content_padding" - android:clipChildren="false" - android:clipToPadding="false" /> + android:clipToPadding="false" + android:clipChildren="false" /> </com.android.systemui.statusbar.phone.NearestTouchFrame> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index be80d52f2a57..79e1fae98c21 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 9e4810cb08ca..009ba4861af1 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.AttributeSet; 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 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe mSecurityViewFlipper.addView(v); updateSecurityView(v); view = (KeyguardSecurityView)v; + view.reset(); } return view; @@ -209,7 +208,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe 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 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } 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 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe showWipeDialog(failedAttempts, userType); } } - monitor.reportFailedStrongAuthUnlockAttempt(userId); mLockPatternUtils.reportFailedPasswordAttempt(userId); if (timeoutMs > 0) { mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); @@ -433,7 +431,6 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe 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 ef3aa42727e9..0e2181532630 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -209,9 +209,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { // 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { 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 79302f2aa2ff..16b54b4cea5b 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.PixelFormat; 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.view.WindowManager; 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 @@ import com.android.systemui.util.leak.RotationUtils; * 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { @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 @@ public class ScreenDecorations extends SystemUI implements Tunable { // - 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; + if (DEBUG) { + Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at " + + mRotation); + } + mOverlay.getViewTreeObserver().addOnPreDrawListener( - new RestartingPreDrawListener(mOverlay)); + new RestartingPreDrawListener(mOverlay, newRotation)); mBottomOverlay.getViewTreeObserver().addOnPreDrawListener( - new RestartingPreDrawListener(mBottomOverlay)); - + 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { .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 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { @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 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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() { - mPendingRotationChange = false; 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() { + 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 89688fba1cc6..33db2c8bc16f 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 @@ public class KeyguardViewMediator extends SystemUI { 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 da41136767aa..2e5eb342347b 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { || 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 9a648d17c4ff..0b9067e5dc1f 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 @@ public class PowerUI extends SystemUI { @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 @@ public class PowerUI extends SystemUI { 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 0876a5d3f456..3fc258b1e8e9 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 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne 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 53a576d3519d..591e9e015897 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 @@ public class TileQueryHelper { 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 834feb7781ea..022a2b4a5fbf 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 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { 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 class QSTileImpl<TState extends State> implements QSTile { 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 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { 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 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { } 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 06f26c9cbc7c..469c3c2c60b1 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 306319903ecb..a215ec6ecafa 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 class NotificationShelf extends ActivatableNotificationView implements } 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 7e6abe95e226..5c18782727df 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 @@ public class NotificationPanelView extends PanelView implements mQsExpansionHeight = height; updateQsExpansion(); requestScrollerTopPaddingUpdate(false /* animate */); - if (mKeyguardShowing) { - updateHeaderKeyguardAlpha(); - } + updateHeaderKeyguardAlpha(); if (mStatusBarState == StatusBarState.SHADE_LOCKED || mStatusBarState == StatusBarState.KEYGUARD) { updateKeyguardBottomAreaAlpha(); @@ -1763,6 +1761,9 @@ public class NotificationPanelView extends PanelView implements } 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 bd73a4064908..d68e2fa34cbc 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 @@ public class QuickStepController implements GestureHelper { 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 fadc0eac9e73..a38328a8161e 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 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D 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 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D 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 d6d0673e2c0b..3c16329e6f19 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 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof @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 d7c4bbf3ea1d..c97095e1860b 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.Context; 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 @@ abstract public class SafetyWarningDialog extends SystemUIDialog 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 @@ abstract public class SafetyWarningDialog extends SystemUIDialog @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 f1bf31d7a58a..cc969177ab2e 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 com.android.systemui.tuner.TunablePadding.FLAG_START; 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 static org.mockito.Mockito.when; 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 @@ import org.junit.runner.RunWith; @SmallTest public class ScreenDecorationsTest extends SysuiTestCase { + private TestableLooper mTestableLooper; private ScreenDecorations mScreenDecorations; private StatusBar mStatusBar; private WindowManager mWindowManager; @@ -71,6 +75,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { @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 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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 5ecf0c04aeb1..a9d49f91e44e 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 @@ public class PowerUITest extends SysuiTestCase { } @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 @@ public class PowerUITest extends SysuiTestCase { } @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 754ba722d081..b08924b8adb6 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 68c2dcbbe3f6..0a106fa0c08f 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 49896773ac55..0bf83306f875 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 6dcbbd923601..bcc7c9756a6e 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 f4b9f7ea7c37..0fcbdebbd345 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 016839232255..1509fc00fb1d 100644 --- a/proto/src/gnss.proto +++ b/proto/src/gnss.proto @@ -45,6 +45,9 @@ message GnssLog { // 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 03ab60c33f51..b990175fd616 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -941,9 +941,10 @@ message MetricsEvent { // 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 @@ message MetricsEvent { // 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; + // OPEN: Emergency dialer opened // CLOSE: Emergency dialer closed // SUBTYPE: The entry type that user opened emergency dialer diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 72f11e0a63c1..b29c992120d4 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -457,6 +457,11 @@ message WifiLog { // 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 @@ message WifiRttLog { 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 c9c7adc45697..f69b6387a605 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 @@ public class AppWidgetService extends SystemService { } @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 db8ad12cfdf8..b71d7a726b28 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 @@ package com.android.server.appwidget; 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 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } - 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 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } } - 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 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku 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 dc84498353ea..58823036212d 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 @@ final class SaveUi { 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 @@ final class SaveUi { if (mDone) { return; } - mDone = true; mRealListener.onSave(); } @@ -106,7 +112,6 @@ final class SaveUi { 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 5c14459da566..50f15ca0739f 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -624,7 +624,7 @@ public final class BatteryService extends SystemService { // 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 f5b29e9b76b8..0deaee7f7878 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.Looper; 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.IOException; 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 @@ public final class PinnerService extends SystemService { 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 @@ public final class PinnerService extends SystemService { 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 @@ public final class PinnerService extends SystemService { */ @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 @@ public final class PinnerService extends SystemService { } 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 6550d06b8a12..9bf72fb86cd6 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 @@ final class ActivityManagerConstants extends ContentObserver { // 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 @@ final class ActivityManagerConstants extends ContentObserver { // 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { @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 @@ final class ActivityManagerConstants extends ContentObserver { } } + 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 1dec3bf66ba6..904d8f058bb5 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } - // 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (allowed) { - return -1; + return allowedResult; } } @@ -10927,6 +10934,20 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * @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 @@ public class ActivityManagerService extends IActivityManager.Stub packageUid, packageName, intents, resolvedTypes, null /* resultTo */, SafeActivityOptions.fromBundle(bOptions), userId, - false /* validateIncomingUser */); + false /* validateIncomingUser */, null /* originatingPendingIntent */); } } @@ -26718,6 +26739,18 @@ public class ActivityManagerService extends IActivityManager.Stub 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 dc9a5adb5a0c..093bd87813d5 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 47d0423550c4..9ffa6627836f 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 @@ package com.android.server.am; 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_FULLSCREEN; 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_TR 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.MemoryStat; 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 @@ class ActivityMetricsLogger { 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 75f27231c976..60f79f720242 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 class ActivityRecord extends ConfigurationContainer implements AppWindowCo 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 c520101d3ff4..2ae056fe18a5 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 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 a7c32009a4c4..edcf6e7bd516 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 @@ public class ActivityStartController { 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 @@ public class ActivityStartController { .setActivityOptions(options) .setMayWait(userId) .setInTask(inTask) + .setOriginatingPendingIntent(originatingPendingIntent) .execute(); } @@ -278,10 +280,12 @@ public class ActivityStartController { * @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 @@ public class ActivityStartController { // 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 @@ public class ActivityStartController { // 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 73e3d33073fc..00ba3a61d1d6 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.Bundle; 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 @@ class ActivityStarter { int userId; WaitResult waitResult; int filterCallingUid; + PendingIntentRecord originatingPendingIntent; /** * If set to {@code true}, allows this activity start to look into @@ -369,6 +371,7 @@ class ActivityStarter { avoidMoveToFront = false; allowPendingRemoteAnimationRegistryLookup = true; filterCallingUid = UserHandle.USER_NULL; + originatingPendingIntent = null; } /** @@ -407,6 +410,7 @@ class ActivityStarter { allowPendingRemoteAnimationRegistryLookup = request.allowPendingRemoteAnimationRegistryLookup; filterCallingUid = request.filterCallingUid; + originatingPendingIntent = request.originatingPendingIntent; } } @@ -490,7 +494,8 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 a6dafbb1db36..f0e2876b4761 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 @@ class AppErrors { 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 e0aa2a261b3c..4e00304a9da6 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 @@ final class PendingIntentRecord extends IIntentSender.Stub { } 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 @@ final class PendingIntentRecord extends IIntentSender.Stub { 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 caf52e359548..28ebbb87f261 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 @@ final class ProcessRecord { } 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 18c095725b09..415a822e3160 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_IS_CURRENT; 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.IStopUserCallback; 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.SparseArray; 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 @@ class UserController implements Handler.Callback { } } + // 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 @@ class UserController implements Handler.Callback { } } + 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 349e1c8b713e..512e85192d36 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 @@ final class DisplayDeviceInfo { 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 @@ final class DisplayDeviceInfo { 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 ddd8855f3199..cc5a8271eb5f 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 @@ public final class DisplayManagerService extends SystemService { // 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 @@ public final class DisplayManagerService extends SystemService { // 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 @@ public final class DisplayManagerService extends SystemService { 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 @@ public final class DisplayManagerService extends SystemService { PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting(); mCurrentUserId = UserHandle.USER_SYSTEM; + + mSystemReady = false; } public void setupSchedulerPolicies() { @@ -400,6 +414,10 @@ public final class DisplayManagerService extends SystemService { 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 @@ public final class DisplayManagerService extends SystemService { 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 @@ public final class DisplayManagerService extends SystemService { 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 @@ public final class DisplayManagerService extends SystemService { configureColorModeLocked(display, device); if (isDefault) { recordStableDisplayStatsIfNeededLocked(display); + recordTopInsetLocked(display); } mLogicalDisplays.put(displayId, display); @@ -1039,6 +1065,21 @@ public final class DisplayManagerService extends SystemService { } } + 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 @@ public final class DisplayManagerService extends SystemService { 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 21ae048e1d75..16d82df4dd5b 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 @@ final class LocalDisplayAdapter extends DisplayAdapter { && 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 23ee56b24b19..5b7c5205ce3a 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 @@ package com.android.server.display; 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 @@ import java.util.Objects; * </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 @@ final class LogicalDisplay { 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 @@ final class LogicalDisplay { 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 @@ final class LogicalDisplay { } /** + * 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 @@ final class LogicalDisplay { 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 @@ final class LogicalDisplay { 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 60e9eaab5721..e7459a40a9da 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @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 c0fbfbb20b95..18f4bc768632 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 @@ public class ConditionProviders extends ManagedServices { 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 1284468947c2..c6e71e53d595 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 @@ public class NotificationManagerService extends SystemService { 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 67608753a2c3..b016fafa3d29 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 @@ import java.util.List; 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 63c0bafe389d..b080a73c1e42 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 @@ package com.android.server.notification; 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.ArrayMap; 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 @@ public class ZenModeConditions implements ConditionProviders.Callback { 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 @@ public class ZenModeConditions implements ConditionProviders.Callback { 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 @@ public class ZenModeConditions implements ConditionProviders.Callback { 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 @@ public class ZenModeConditions implements ConditionProviders.Callback { @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 @@ public class ZenModeConditions implements ConditionProviders.Callback { 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 @@ public class ZenModeConditions implements ConditionProviders.Callback { 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 669d5565534d..0c42f8ab8345 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { config.user = user; } synchronized (mConfig) { - setConfigLocked(config, reason); + setConfigLocked(config, null, reason); } cleanUpZenRules(); } @@ -312,7 +312,7 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { } 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { newConfig.automaticRules.removeAt(i); } } - return setConfigLocked(newConfig, reason, true); + return setConfigLocked(newConfig, reason, null, true); } } @@ -537,7 +537,7 @@ public class ZenModeHelper { newRule.enabler = caller; newConfig.manualRule = newRule; } - setConfigLocked(newConfig, reason, setRingerMode); + setConfigLocked(newConfig, reason, null, setRingerMode); } } @@ -644,7 +644,7 @@ public class ZenModeHelper { } if (DEBUG) Log.d(TAG, reason); synchronized (mConfig) { - setConfigLocked(config, reason); + setConfigLocked(config, null, reason); } } } @@ -673,7 +673,7 @@ public class ZenModeHelper { synchronized (mConfig) { final ZenModeConfig newConfig = mConfig.copy(); newConfig.applyNotificationPolicy(policy); - setConfigLocked(newConfig, "setNotificationPolicy"); + setConfigLocked(newConfig, null, "setNotificationPolicy"); } } @@ -697,7 +697,7 @@ public class ZenModeHelper { } } } - setConfigLocked(newConfig, "cleanUpZenRules"); + setConfigLocked(newConfig, null, "cleanUpZenRules"); } } @@ -710,17 +710,19 @@ public class ZenModeHelper { } } - 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { } } - 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 f082271ab094..c73870189002 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_CHANGED; 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.Intent; 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 @@ public final class OverlayManagerService extends SystemService { @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 cf49d2a55d61..95c70d590b69 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 android.util.Slog; 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 @@ public class PackageDexOptimizer { 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 @@ public class PackageDexOptimizer { } } + 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 29047e756f71..62c49e2d2ee5 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); //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 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } 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 0ba78226a38f..21daa39e05e0 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 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { 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 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { 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 a042fedf8b47..c3f23a81518a 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 class PermissionManagerInternal { */ 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 @@ public abstract class PermissionManagerInternal { /** 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 c51a72406b53..02c9049f008e 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.Manifest; 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.PermissionGroupInfo; 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 @@ public class PermissionManagerService { " 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 @@ public class PermissionManagerService { } - 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 @@ public class PermissionManagerService { 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 @@ public class PermissionManagerService { } } } + revokeAllPermissions(bps, allPackageNames, permissionCallback); if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } @@ -1490,9 +1547,10 @@ public class PermissionManagerService { } } - - 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 @@ public class PermissionManagerService { 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 @@ public class PermissionManagerService { 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 @@ public class PermissionManagerService { 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 eca6f9f1ec47..14c985c090a3 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 @@ public class BarController { } 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 dfb617999668..9a741bcfc3d6 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_ROUNDED_CO 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 44136661bee5..f9f4bbfc8eb0 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.RemoteException; 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.IWindowManager; 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 @@ public class TrustManagerService extends SystemService { 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 @@ public class TrustManagerService extends SystemService { 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 b2a12bef5283..86f328d248db 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.IBinder; 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 @@ public class BoundsAnimationController { 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 @@ public class BoundsAnimationController { 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 2887e5ef9061..2941e93d12dc 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo 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 f25ec5cd935e..efb43a6b90cf 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 static android.view.Surface.ROTATION_90; import android.graphics.Matrix; import android.view.DisplayInfo; +import android.view.Surface.Rotation; import com.android.server.wm.utils.CoordinateTransforms; @@ -65,6 +66,16 @@ public class ForcedSeamlessRotator { } /** + * 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 class ForcedSeamlessRotator { 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 fa8a5c66aeea..755a571cf5f7 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.DisplayInfo; 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 @@ class ScreenRotationAnimation { .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 8bc224636c1e..8b4a2dd36e6c 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 @@ public class WindowManagerService extends IWindowManager.Stub mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier); final AnimationHandler animationHandler = new AnimationHandler(); - animationHandler.setProvider(new SfVsyncFrameCallbackProvider()); mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition, AnimationThread.getHandler(), animationHandler); @@ -6221,6 +6220,17 @@ public class WindowManagerService extends IWindowManager.Stub } /** + * 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 009f3930d02e..1ae680f793ca 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 b4a998add374..c8600dd151d2 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 @@ public class InsetUtils { } /** + * 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 b74a582db2de..6ee7d4931c18 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 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { 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 82a28954a8c6..e91780239c7f 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.Configuration; 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 @@ public final class SystemServer { // 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 1520859d4aac..8d056fc4a8c0 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 android.view.Gravity; 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.any; 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 @@ public class ActivityStarterTests extends ActivityTestsBase { 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 @@ public class ActivityStarterTests extends ActivityTestsBase { 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 @@ public class ActivityStarterTests extends ActivityTestsBase { 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 d0f0fe315bcf..08bcc3d751f2 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 @@ public class InsetUtilsTest { 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 afc12636007f..8222c386c0d9 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.times; 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.AudioManager; 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 android.util.Xml; 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 @@ import java.io.ByteArrayOutputStream; @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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 66c1a3c0ffbc..17847eaa0ca5 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -954,16 +954,15 @@ public class WifiEnterpriseConfig implements Parcelable { * 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 */ |