diff options
91 files changed, 1537 insertions, 361 deletions
diff --git a/Android.bp b/Android.bp index 05c7dbcba02e..0acc3d69a597 100644 --- a/Android.bp +++ b/Android.bp @@ -384,6 +384,7 @@ java_defaults { "core/java/android/view/IRecentsAnimationRunner.aidl", "core/java/android/view/IRemoteAnimationFinishedCallback.aidl", "core/java/android/view/IRotationWatcher.aidl", + "core/java/android/view/ISystemGestureExclusionListener.aidl", "core/java/android/view/IWallpaperVisibilityListener.aidl", "core/java/android/view/IWindow.aidl", "core/java/android/view/IWindowFocusObserver.aidl", @@ -753,10 +754,6 @@ java_defaults { "android.hardware.radio-V1.2-java", "android.hardware.radio-V1.3-java", "android.hardware.radio-V1.4-java", - "android.hardware.radio.config-V1.0-java", - "android.hardware.radio.config-V1.1-java", - "android.hardware.radio.config-V1.2-java", - "android.hardware.radio.deprecated-V1.0-java", "android.hardware.thermal-V1.0-java-constants", "android.hardware.thermal-V1.0-java", "android.hardware.thermal-V1.1-java", diff --git a/api/current.txt b/api/current.txt index 8ff63c07594d..34c2c2942ded 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11051,6 +11051,7 @@ package android.content.pm { method public void dump(android.util.Printer, String); method public static CharSequence getCategoryTitle(android.content.Context, int); method public boolean isProfileableByShell(); + method public boolean isResourceOverlay(); method public boolean isVirtualPreload(); method public CharSequence loadDescription(android.content.pm.PackageManager); field public static final int CATEGORY_AUDIO = 1; // 0x1 @@ -25082,6 +25083,7 @@ package android.media { field public static final String KEY_LANGUAGE = "language"; field public static final String KEY_LATENCY = "latency"; field public static final String KEY_LEVEL = "level"; + field public static final String KEY_MAX_BFRAMES = "max-bframes"; field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder"; field public static final String KEY_MAX_HEIGHT = "max-height"; field public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; @@ -50442,6 +50444,7 @@ package android.view { method protected float getLeftFadingEdgeStrength(); method protected int getLeftPaddingOffset(); method public final boolean getLocalVisibleRect(android.graphics.Rect); + method public void getLocationInSurface(@NonNull @Size(2) int[]); method public void getLocationInWindow(@Size(2) int[]); method public void getLocationOnScreen(@Size(2) int[]); method public android.graphics.Matrix getMatrix(); diff --git a/api/system-current.txt b/api/system-current.txt index 47e2b5bd5cfe..583dd7691798 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1479,6 +1479,7 @@ package android.content.om { } public class OverlayManager { + method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle); method public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@Nullable String, int); method public boolean setEnabled(@Nullable String, boolean, int); method public boolean setEnabledExclusiveInCategory(@Nullable String, int); @@ -3067,6 +3068,19 @@ package android.location { method public void onLocationBatch(java.util.List<android.location.Location>); } + public final class GnssCapabilities { + method public boolean hasCapability(int); + field public static final int GEOFENCING = 2; // 0x2 + field public static final int LOW_POWER_MODE = 0; // 0x0 + field public static final int MEASUREMENTS = 3; // 0x3 + field public static final int MEASUREMENT_CORRECTIONS = 5; // 0x5 + field public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 7; // 0x7 + field public static final int MEASUREMENT_CORRECTIONS_LOS_SATS = 6; // 0x6 + field public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 8; // 0x8 + field public static final int NAV_MESSAGES = 4; // 0x4 + field public static final int SATELLITE_BLACKLIST = 1; // 0x1 + } + public final class GnssMeasurementCorrections implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters(); @@ -3374,7 +3388,7 @@ package android.location { public class LocationManager { method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch(); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize(); - method public int getGnssCapabilities(); + method @Nullable public android.location.GnssCapabilities getGnssCapabilities(); method @Nullable public String getLocationControllerExtraPackage(); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections); method public boolean isLocationControllerExtraPackageEnabled(); @@ -5885,6 +5899,7 @@ package android.provider { field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native"; field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; field public static final String NAMESPACE_SCHEDULER = "scheduler"; + field public static final String NAMESPACE_STORAGE = "storage"; field public static final String NAMESPACE_SYSTEMUI = "systemui"; field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier"; } @@ -5913,11 +5928,6 @@ package android.provider { method @Nullable public String getString(@NonNull String, @Nullable String); } - public static interface DeviceConfig.Storage { - field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; - field public static final String NAMESPACE = "storage"; - } - public static interface DeviceConfig.Telephony { field public static final String NAMESPACE = "telephony"; field public static final String RAMPING_RINGER_DURATION = "ramping_ringer_duration"; @@ -6119,6 +6129,7 @@ package android.provider { field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode"; field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications"; field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications"; + field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages"; field public static final String USER_SETUP_COMPLETE = "user_setup_complete"; field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa @@ -6448,6 +6459,7 @@ package android.service.contentcapture { method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; + field public static final String SERVICE_META_DATA = "android.content_capture"; } public final class SnapshotData implements android.os.Parcelable { @@ -8576,7 +8588,7 @@ package android.telephony.ims { field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants; } - public class ImsException extends java.lang.Exception { + public final class ImsException extends java.lang.Exception { ctor public ImsException(@Nullable String); ctor public ImsException(@Nullable String, int); ctor public ImsException(@Nullable String, int, @Nullable Throwable); diff --git a/api/system-removed.txt b/api/system-removed.txt index 18d0ec02f077..7e044698c72c 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -60,14 +60,6 @@ package android.content { } -package android.content.pm { - - public static class PackageInstaller.SessionParams implements android.os.Parcelable { - method @Deprecated public void setEnableRollback(); - } - -} - package android.location { public class LocationManager { diff --git a/api/test-current.txt b/api/test-current.txt index 17ef7ee02e24..e3fea0aef795 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2416,6 +2416,7 @@ package android.service.contentcapture { method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; + field public static final String SERVICE_META_DATA = "android.content_capture"; } public final class SnapshotData implements android.os.Parcelable { diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 2a39c2fd4f59..9afdd437491f 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -436,7 +436,7 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets( continue; } - if (!enforce_overlayable) { + if (enforce_overlayable) { Result<Unit> success = CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid); if (!success) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index efd9990f4ade..93a9daced987 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2438,7 +2438,7 @@ public class Intent implements Parcelable, Cloneable { * Broadcast Action: A rollback has been committed. * * <p class="note">This is a protected intent that can only be sent - * by the system. + * by the system. The receiver must hold MANAGE_ROLLBACK permission. * * @hide */ diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index 8e72fa5e1cfd..ceea0435a254 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -16,12 +16,14 @@ package android.content.om; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import java.util.List; @@ -96,6 +98,28 @@ public class OverlayManager { } /** + * Returns information about the overlay with the given package name for + * the specified user. + * + * @param packageName The name of the package. + * @param userHandle The user to get the OverlayInfos for. + * @return An OverlayInfo object; if no overlays exist with the + * requested package name, null is returned. + * + * @hide + */ + @SystemApi + @Nullable + public OverlayInfo getOverlayInfo(@NonNull final String packageName, + @NonNull final UserHandle userHandle) { + try { + return mService.getOverlayInfo(packageName, userHandle.myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns information about all overlays for the given target package for * the specified user. The returned list is ordered according to the * overlay priority with the highest priority at the end of the list. diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 706cbbf560c5..068a93a253ff 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -671,6 +671,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE = 1 << 27; + /** + * Indicates whether this package is in fact a runtime resource overlay. + * + * @hide + */ + public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28; + + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -683,6 +691,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_HAS_DOMAIN_URLS, PRIVATE_FLAG_HIDDEN, PRIVATE_FLAG_INSTANT, + PRIVATE_FLAG_IS_RESOURCE_OVERLAY, PRIVATE_FLAG_ISOLATED_SPLIT_LOADING, PRIVATE_FLAG_OEM, PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, @@ -2023,6 +2032,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } /** + * Returns true if the package has declared in its manifest that it is a + * runtime resource overlay. + */ + public boolean isResourceOverlay() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY) != 0; + } + + /** * @hide */ @Override protected ApplicationInfo getApplicationInfo() { diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 33b9c724de21..3edd17a4bb1f 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1448,19 +1448,6 @@ public class PackageInstaller { } /** - * Request that rollbacks be enabled for the given upgrade. - * - * @removed - * @deprecated use {@link #setEnableRollback(boolean)} instead. - * @hide - */ - @Deprecated - @SystemApi - public void setEnableRollback() { - installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; - } - - /** * Request that rollbacks be enabled or disabled for the given upgrade. * * @param enable set to {@code true} to enable, {@code false} to disable diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 9d0ece0220b4..743a302cc543 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2108,6 +2108,9 @@ public class PackageParser { return null; } + pkg.applicationInfo.privateFlags |= + ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY; + XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_KEY_SETS)) { diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index 13c49a072277..3488cc30892c 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -307,9 +307,9 @@ public final class SharedLibraryInfo implements Parcelable { @Override public String toString() { - return "SharedLibraryInfo[name:" + mName + ", type:" + typeToString(mType) + return "SharedLibraryInfo{name:" + mName + ", type:" + typeToString(mType) + ", version:" + mVersion + (!getDependentPackages().isEmpty() - ? " has dependents" : ""); + ? " has dependents" : "") + "}"; } @Override diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 67292426b248..6b8416d46601 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -191,9 +191,9 @@ public class Resources { /** * Return a global shared Resources object that provides access to only - * system resources (no application resources), and is not configured for - * the current screen (can not use dimension units, does not change based - * on orientation, etc). + * system resources (no application resources), is not configured for the + * current screen (can not use dimension units, does not change based on + * orientation, etc), and is not affected by Runtime Resource Overlay. */ public static Resources getSystem() { synchronized (sSync) { diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index d796003395f5..5e2875d02d90 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -176,6 +176,6 @@ public final class SQLiteGlobal { /** @hide */ public static boolean checkDbWipe() { - return true; + return false; } } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 7bd0fe23f1a3..7fc07b05771c 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -225,6 +225,14 @@ public final class DeviceConfig { public static final String NAMESPACE_SCHEDULER = "scheduler"; /** + * Namespace for storage-related features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_STORAGE = "storage"; + + /** * Namespace for System UI related features. * * @hide @@ -294,23 +302,6 @@ public final class DeviceConfig { String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration"; } - /** - * Namespace for storage-related features. - * - * @hide - */ - @SystemApi - public interface Storage { - String NAMESPACE = "storage"; - - /** - * If {@code 1}, enables the isolated storage feature. If {@code -1}, - * disables the isolated storage feature. If {@code 0}, uses the default - * value from the build system. - */ - String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; - } - private static final Object sLock = new Object(); @GuardedBy("sLock") private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners = diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java index e931826d2455..8f772d4ec780 100644 --- a/core/java/android/provider/FontsContract.java +++ b/core/java/android/provider/FontsContract.java @@ -34,7 +34,6 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.net.Uri; -import android.os.Build.VERSION_CODES; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerThread; @@ -652,17 +651,12 @@ public class FontsContract { if (familyBuilder == null) { familyBuilder = new FontFamily.Builder(font); } else { - try { - familyBuilder.addFont(font); - } catch (IllegalArgumentException e) { - if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) { - // Surpress the IllegalArgumentException for keeping the backward - // compatibility. - continue; - } - throw e; - } + familyBuilder.addFont(font); } + } catch (IllegalArgumentException e) { + // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion + // thrown by native code and returns null. + return null; } catch (IOException e) { continue; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b8174e66e8a6..63235a1c17e7 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5607,6 +5607,7 @@ public final class Settings { * * @hide */ + @SystemApi public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 34ced177fed1..96b861b46dd4 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -427,7 +427,7 @@ public abstract class AugmentedAutofillService extends Service { mFocusedValue = focusedValue; if (mCallback != null) { try { - if (mCallback.isCompleted()) { + if (!mCallback.isCompleted()) { mCallback.cancel(); } } catch (RemoteException e) { diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 6f4114d1d81a..df113979bacf 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -78,6 +78,21 @@ public abstract class ContentCaptureService extends Service { public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; + /** + * Name under which a ContentCaptureService component publishes information about itself. + * + * <p>This meta-data should reference an XML resource containing a + * <code><{@link + * android.R.styleable#ContentCaptureService content-capture-service}></code> tag. + * + * <p>This is a a sample XML file configuring a ContentCaptureService: + * <pre> <content-capture-service + * android:settingsActivity="foo.bar.SettingsActivity" + * . . . + * /></pre> + */ + public static final String SERVICE_META_DATA = "android.content_capture"; + private Handler mHandler; private IContentCaptureServiceCallback mCallback; diff --git a/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java new file mode 100644 index 000000000000..6ecd82f50fdb --- /dev/null +++ b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2019 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. + */ + +package android.service.contentcapture; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.RemoteException; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.PrintWriter; + +/** + * {@link ServiceInfo} and meta-data about an {@link ContentCaptureService}. + * + * @hide + */ +public final class ContentCaptureServiceInfo { + + private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName(); + private static final String XML_TAG_SERVICE = "content-capture-service"; + + private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp, + @UserIdInt int userId) throws PackageManager.NameNotFoundException { + int flags = PackageManager.GET_META_DATA; + if (!isTemp) { + flags |= PackageManager.MATCH_SYSTEM_ONLY; + } + + ServiceInfo si = null; + try { + si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId); + } catch (RemoteException e) { + } + if (si == null) { + throw new NameNotFoundException("Could not get serviceInfo for " + + (isTemp ? " (temp)" : "(default system)") + + " " + comp.flattenToShortString()); + } + return si; + } + + @NonNull + private final ServiceInfo mServiceInfo; + + @Nullable + private final String mSettingsActivity; + + public ContentCaptureServiceInfo(@NonNull Context context, @NonNull ComponentName comp, + boolean isTemporaryService, @UserIdInt int userId) + throws PackageManager.NameNotFoundException { + this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId)); + } + + private ContentCaptureServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) { + // Check for permissions. + if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) { + Slog.w(TAG, "ContentCaptureService from '" + si.packageName + + "' does not require permission " + + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + throw new SecurityException("Service does not require permission " + + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + } + + mServiceInfo = si; + + // Get the metadata, if declared. + final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(), + ContentCaptureService.SERVICE_META_DATA); + if (parser == null) { + mSettingsActivity = null; + return; + } + + String settingsActivity = null; + + try { + final Resources resources = context.getPackageManager().getResourcesForApplication( + si.applicationInfo); + + int type = 0; + while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { + type = parser.next(); + } + + if (XML_TAG_SERVICE.equals(parser.getName())) { + final AttributeSet allAttributes = Xml.asAttributeSet(parser); + TypedArray afsAttributes = null; + try { + afsAttributes = resources.obtainAttributes(allAttributes, + com.android.internal.R.styleable.ContentCaptureService); + settingsActivity = afsAttributes.getString( + R.styleable.ContentCaptureService_settingsActivity); + } finally { + if (afsAttributes != null) { + afsAttributes.recycle(); + } + } + } else { + Log.e(TAG, "Meta-data does not start with content-capture-service tag"); + } + } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { + Log.e(TAG, "Error parsing auto fill service meta-data", e); + } + + mSettingsActivity = settingsActivity; + } + + public ServiceInfo getServiceInfo() { + return mServiceInfo; + } + + @Nullable + public String getSettingsActivity() { + return mSettingsActivity; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append("[").append(mServiceInfo); + builder.append(", settings:").append(mSettingsActivity); + return builder.toString(); + } + + /** + * Dumps it! + */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); + pw.print("Component: "); + pw.println(getServiceInfo().getComponentName()); + pw.print(prefix); + pw.print("Settings: "); + pw.println(mSettingsActivity); + } +} diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java index 7fb0f950f583..610cf2c7c784 100644 --- a/core/java/android/text/style/LineHeightSpan.java +++ b/core/java/android/text/style/LineHeightSpan.java @@ -70,7 +70,15 @@ public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { * Default implementation of the {@link LineHeightSpan}, which changes the line height of the * attached paragraph. * <p> - * LineHeightSpan will change the line height of the entire paragraph, even though it + * For example, a paragraph with its line height equal to 100px can be set like this: + * <pre> + * SpannableString string = new SpannableString("This is a multiline paragraph. This is a multiline paragraph."); + * string.setSpan(new LineHeightSpan.Standard(100), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + * </pre> + * <img src="{@docRoot}reference/android/images/text/style/lineheightspan.png" /> + * <figcaption>Text with line height set to 100 pixels.</figcaption> + * <p> + * Notice that LineHeightSpan will change the line height of the entire paragraph, even though it * covers only part of the paragraph. * </p> */ diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl new file mode 100644 index 000000000000..a032625547d2 --- /dev/null +++ b/core/java/android/view/ISystemGestureExclusionListener.aidl @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2019, 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. + */ + +package android.view; + +import android.graphics.Region; + +/** + * Listener for changes to the system gesture exclusion region + * + * {@hide} + */ +oneway interface ISystemGestureExclusionListener { + /** + * Called when the system gesture exclusion for the given display changed. + * @param displayId the display whose system gesture exclusion changed + * @param systemGestureExclusion a {@code Region} where the app would like priority over the + * system gestures, in display coordinates. + */ + void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion); +}
\ No newline at end of file diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 9ee6585d243f..b91b93f7e09c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -40,6 +40,7 @@ import android.view.IOnKeyguardExitResult; import android.view.IPinnedStackListener; import android.view.RemoteAnimationAdapter; import android.view.IRotationWatcher; +import android.view.ISystemGestureExclusionListener; import android.view.IWallpaperVisibilityListener; import android.view.IWindowSession; import android.view.IWindowSessionCallback; @@ -281,6 +282,18 @@ interface IWindowManager int displayId); /** + * Registers a system gesture exclusion listener for a given display. + */ + void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId); + + /** + * Unregisters a system gesture exclusion listener for a given display. + */ + void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId); + + /** * Used only for assist -- request a screenshot of the current application. */ boolean requestAssistScreenshot(IAssistDataReceiver receiver); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 1fcd4321cdde..87efb3fbf6c0 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -32,6 +32,8 @@ import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; +import java.util.List; + /** * System private per-application interface to the window manager. * @@ -265,4 +267,10 @@ interface IWindowSession { * that new state. */ void insetsModified(IWindow window, in InsetsState state); + + + /** + * Called when the system gesture exclusion has changed. + */ + void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ab2cc6669631..bf0f4e29a4f3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11095,11 +11095,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>Computes the coordinates of this view in its surface. The argument * must be an array of two integers. After the method returns, the array * contains the x and y location in that order.</p> - * @hide + * * @param location an array of two integers in which to hold the coordinates */ - @UnsupportedAppUsage - public void getLocationInSurface(@Size(2) int[] location) { + public void getLocationInSurface(@NonNull @Size(2) int[] location) { getLocationInWindow(location); if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a28d6622c40f..6d04cd3187ef 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3987,7 +3987,11 @@ public final class ViewRootImpl implements ViewParent, void systemGestureExclusionChanged() { final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects(); if (rectsForWindowManager != null) { - // TODO Send to WM + try { + mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } mAttachInfo.mTreeObserver .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager); } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index b6ec5f936fbd..c9ef038b78de 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -4984,9 +4984,6 @@ public class Editor { if (magnifierTopLeft == null) { return; } - final Rect surfaceInsets = - mTextView.getViewRootImpl().mWindowAttributes.surfaceInsets; - magnifierTopLeft.offset(-surfaceInsets.left, -surfaceInsets.top); final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y, magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(), magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight()); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 50e883679eb9..08799cfb5d4c 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -471,13 +471,13 @@ public final class Magnifier { } /** - * Returns the top left coordinates of the magnifier, relative to the surface of the - * main application window. They will be determined by the coordinates of the last - * {@link #show(float, float)} or {@link #show(float, float, float, float)} call, adjusted - * to take into account any potential clamping behavior. The method can be used immediately - * after a #show call to find out where the magnifier will be positioned. However, the - * position of the magnifier will not be updated in the same frame due to the async - * copying of the content copying and of the magnifier rendering. + * Returns the top left coordinates of the magnifier, relative to the main application + * window. They will be determined by the coordinates of the last {@link #show(float, float)} + * or {@link #show(float, float, float, float)} call, adjusted to take into account any + * potential clamping behavior. The method can be used immediately after a #show + * call to find out where the magnifier will be positioned. However, the position of the + * magnifier will not be updated visually in the same frame, due to the async nature of + * the content copying and of the magnifier rendering. * The method will return {@code null} if #show has not yet been called, or if the last * operation performed was a #dismiss. * @@ -488,15 +488,18 @@ public final class Magnifier { if (mWindow == null) { return null; } - return new Point(getCurrentClampedWindowCoordinates()); + final Point position = getCurrentClampedWindowCoordinates(); + position.offset(-mParentSurface.mInsets.left, -mParentSurface.mInsets.top); + return new Point(position); } /** * Returns the top left coordinates of the magnifier source (i.e. the view region going to - * be magnified and copied to the magnifier), relative to the surface the content is copied - * from. The content will be copied: + * be magnified and copied to the magnifier), relative to the window or surface the content + * is copied from. The content will be copied: * - if the magnified view is a {@link SurfaceView}, from the surface backing it - * - otherwise, from the surface of the main application window + * - otherwise, from the surface backing the main application window, and the coordinates + * returned will be relative to the main application window * The method will return {@code null} if #show has not yet been called, or if the last * operation performed was a #dismiss. * @@ -507,7 +510,9 @@ public final class Magnifier { if (mWindow == null) { return null; } - return new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top); + final Point position = new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top); + position.offset(-mContentCopySurface.mInsets.left, -mContentCopySurface.mInsets.top); + return new Point(position); } /** @@ -531,7 +536,7 @@ public final class Magnifier { viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; validMainWindowSurface = new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface, - surfaceWidth, surfaceHeight, true); + surfaceWidth, surfaceHeight, surfaceInsets, true); } } // Get the surface backing the magnified view, if it is a SurfaceView. @@ -544,7 +549,7 @@ public final class Magnifier { if (sc != null && sc.isValid()) { final Rect surfaceFrame = surfaceHolder.getSurfaceFrame(); validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface, - surfaceFrame.right, surfaceFrame.bottom, false); + surfaceFrame.right, surfaceFrame.bottom, new Rect(), false); } } @@ -708,9 +713,13 @@ public final class Magnifier { final Rect windowBounds; if (mParentSurface.mIsMainWindowSurface) { final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); - windowBounds = new Rect(systemInsets.left, systemInsets.top, - mParentSurface.mWidth - systemInsets.right, - mParentSurface.mHeight - systemInsets.bottom); + windowBounds = new Rect( + systemInsets.left + mParentSurface.mInsets.left, + systemInsets.top + mParentSurface.mInsets.top, + mParentSurface.mWidth - systemInsets.right - mParentSurface.mInsets.right, + mParentSurface.mHeight - systemInsets.bottom + - mParentSurface.mInsets.bottom + ); } else { windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight); } @@ -725,21 +734,23 @@ public final class Magnifier { * Contains a surface and metadata corresponding to it. */ private static class SurfaceInfo { - public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false); + public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, null, false); private Surface mSurface; private SurfaceControl mSurfaceControl; private int mWidth; private int mHeight; + private Rect mInsets; private boolean mIsMainWindowSurface; SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface, - final int width, final int height, + final int width, final int height, final Rect insets, final boolean isMainWindowSurface) { mSurfaceControl = surfaceControl; mSurface = surface; mWidth = width; mHeight = height; + mInsets = insets; mIsMainWindowSurface = isMainWindowSurface; } } diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING new file mode 100644 index 000000000000..ee378ff72218 --- /dev/null +++ b/core/java/android/widget/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsWidgetTestCases", + "options": [ + { + "instrumentation-arg": "size:=small" + } + ] + } + ] +} diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 4773e168fffa..3205b5aef281 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -20,12 +20,16 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; +import android.graphics.Path; import android.graphics.RectF; +import android.graphics.Region; import android.hardware.input.InputManager; import android.hardware.input.InputManager.InputDeviceListener; +import android.os.RemoteException; import android.os.SystemProperties; import android.util.Log; import android.util.Slog; +import android.view.ISystemGestureExclusionListener; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; @@ -34,6 +38,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowInsets; +import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicyConstants.PointerEventListener; import java.util.ArrayList; @@ -124,12 +129,16 @@ public class PointerLocationView extends View implements InputDeviceListener, private int mActivePointerId; private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); private final PointerCoords mTempCoords = new PointerCoords(); - + + private final Region mSystemGestureExclusion = new Region(); + private final Path mSystemGestureExclusionPath = new Path(); + private final Paint mSystemGestureExclusionPaint; + private final VelocityTracker mVelocity; private final VelocityTracker mAltVelocity; private final FasterStringBuilder mText = new FasterStringBuilder(); - + private boolean mPrintCoords = true; public PointerLocationView(Context c) { @@ -168,7 +177,11 @@ public class PointerLocationView extends View implements InputDeviceListener, mPathPaint.setARGB(255, 0, 96, 255); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(1); - + + mSystemGestureExclusionPaint = new Paint(); + mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0); + mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE); + PointerState ps = new PointerState(); mPointers.add(ps); mActivePointerId = 0; @@ -236,6 +249,12 @@ public class PointerLocationView extends View implements InputDeviceListener, final int NP = mPointers.size(); + if (!mSystemGestureExclusion.isEmpty()) { + mSystemGestureExclusionPath.reset(); + mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath); + canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint); + } + // Labels if (mActivePointerId >= 0) { final PointerState ps = mPointers.get(mActivePointerId); @@ -719,6 +738,12 @@ public class PointerLocationView extends View implements InputDeviceListener, super.onAttachedToWindow(); mIm.registerInputDeviceListener(this, getHandler()); + try { + WindowManagerGlobal.getWindowManagerService().registerSystemGestureExclusionListener( + mSystemGestureExclusionListener, mContext.getDisplayId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } logInputDevices(); } @@ -727,6 +752,12 @@ public class PointerLocationView extends View implements InputDeviceListener, super.onDetachedFromWindow(); mIm.unregisterInputDeviceListener(this); + try { + WindowManagerGlobal.getWindowManagerService().unregisterSystemGestureExclusionListener( + mSystemGestureExclusionListener, mContext.getDisplayId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } @Override @@ -876,4 +907,17 @@ public class PointerLocationView extends View implements InputDeviceListener, return oldLength; } } + + private ISystemGestureExclusionListener mSystemGestureExclusionListener = + new ISystemGestureExclusionListener.Stub() { + @Override + public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) { + Region exclusion = Region.obtain(systemGestureExclusion); + getHandler().post(() -> { + mSystemGestureExclusion.set(exclusion); + exclusion.recycle(); + invalidate(); + }); + } + }; } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 743496fdffb5..9d48fe384f3f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8108,7 +8108,7 @@ <!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a {@link android.service.autofill.AutofillService}, which is referenced from its - {@link android.service.autofill#SERVICE_META_DATA} meta-data entry. + {@link android.service.autofill.AutofillService#SERVICE_META_DATA} meta-data entry. --> <declare-styleable name="AutofillService"> <!-- Fully qualified class name of an activity that allows the user to modify @@ -8134,6 +8134,23 @@ </declare-styleable> <!-- =============================== --> + <!-- Content Capture attributes --> + <!-- =============================== --> + <eat-comment /> + + <!-- Use <code>content-capture-service</code> as the root tag of the XML resource that describes + a {@link android.service.contentcapture.ContentCaptureService}, which is referenced from + its {@link android.service.contentcapture.ContentCaptureService#SERVICE_META_DATA} + meta-data entry. + @hide @SystemApi + --> + <declare-styleable name="ContentCaptureService"> + <!-- Fully qualified class name of an activity that allows the user to modify + the settings for this service. --> + <attr name="settingsActivity" /> + </declare-styleable> + + <!-- =============================== --> <!-- Contacts meta-data attributes --> <!-- =============================== --> <eat-comment /> diff --git a/core/tests/overlaytests/device/assets/package-name.txt b/core/tests/overlaytests/device/assets/package-name.txt new file mode 100644 index 000000000000..809443818f06 --- /dev/null +++ b/core/tests/overlaytests/device/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java index 91fcdbbb18ce..f86743a2fdbc 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java @@ -17,9 +17,12 @@ package com.android.overlaytest; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.UiAutomation; +import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -30,6 +33,8 @@ import android.util.Xml; import androidx.test.InstrumentationRegistry; +import com.android.internal.util.ArrayUtils; + import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -291,6 +296,33 @@ public abstract class OverlayBaseTest { assertEquals(getExpected(no, so, mo), actual); } + @Test + public void testAssetsNotPossibleToOverlay() throws Throwable { + final AssetManager am = mResources.getAssets(); + + // AssetManager#list will include assets from all loaded non-overlay + // APKs, including the framework; framework-res.apk contains at least + // assets/{images,webkit}. Rather than checking the list, verify that + // assets only present in overlays are never part of the list. + String[] files = am.list(""); + assertTrue(ArrayUtils.contains(files, "package-name.txt")); + assertFalse(ArrayUtils.contains(files, "foo.txt")); + assertFalse(ArrayUtils.contains(files, "bar.txt")); + + String contents = null; + try (InputStream is = am.open("package-name.txt")) { + final BufferedReader reader = new BufferedReader( + new InputStreamReader(is, StandardCharsets.UTF_8)); + StringBuilder str = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + str.append(line); + } + contents = str.toString(); + } + assertEquals("com.android.overlaytest", contents); + } + /* * testMatrix* tests * diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt new file mode 100644 index 000000000000..257cc5642cb1 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt @@ -0,0 +1 @@ +foo diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt new file mode 100644 index 000000000000..087cb96b767f --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_one diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt new file mode 100644 index 000000000000..5716ca5987cb --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt @@ -0,0 +1 @@ +bar diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt new file mode 100644 index 000000000000..13185654df21 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_two diff --git a/docs/html/reference/images/text/style/lineheightspan.png b/docs/html/reference/images/text/style/lineheightspan.png Binary files differnew file mode 100644 index 000000000000..18f575392b63 --- /dev/null +++ b/docs/html/reference/images/text/style/lineheightspan.png diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 0d5233880674..9c4b5e8b0165 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1809,6 +1809,45 @@ public abstract class ColorSpace { } /** + * <p>Computes the chromaticity coordinates of a specified correlated color + * temperature (CCT) on the Planckian locus. The specified CCT must be + * greater than 0. A meaningful CCT range is [1667, 25000].</p> + * + * <p>The transform is computed using the methods in Kang et + * al., <i>Design of Advanced Color - Temperature Control System for HDTV + * Applications</i>, Journal of Korean Physical Society 41, 865-871 + * (2002).</p> + * + * @param cct The correlated color temperature, in Kelvin + * @return Corresponding XYZ values + * @throws IllegalArgumentException If cct is invalid + * + * @hide + */ + @NonNull + @Size(3) + public static float[] cctToXyz(@IntRange(from = 1) int cct) { + if (cct < 1) { + throw new IllegalArgumentException("Temperature must be greater than 0"); + } + + final float icct = 1e3f / cct; + final float icct2 = icct * icct; + final float x = cct <= 4000.0f ? + 0.179910f + 0.8776956f * icct - 0.2343589f * icct2 - 0.2661239f * icct2 * icct : + 0.240390f + 0.2226347f * icct + 2.1070379f * icct2 - 3.0258469f * icct2 * icct; + + final float x2 = x * x; + final float y = cct <= 2222.0f ? + -0.20219683f + 2.18555832f * x - 1.34811020f * x2 - 1.1063814f * x2 * x : + cct <= 4000.0f ? + -0.16748867f + 2.09137015f * x - 1.37418593f * x2 - 0.9549476f * x2 * x : + -0.37001483f + 3.75112997f * x - 5.8733867f * x2 + 3.0817580f * x2 * x; + + return xyYToXyz(new float[] {x, y}); + } + + /** * <p>Computes the chromaticity coordinates of a CIE series D illuminant * from the specified correlated color temperature (CCT). The specified CCT * must be greater than 0. A meaningful CCT range is [4000, 25000].</p> diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 9995f1e73018..c8b361bbff2f 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -33,7 +33,6 @@ import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.os.ParcelFileDescriptor; import android.provider.FontRequest; import android.provider.FontsContract; @@ -48,7 +47,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import dalvik.annotation.optimization.CriticalNative; -import dalvik.system.VMRuntime; import libcore.util.NativeAllocationRegistry; @@ -266,16 +264,7 @@ public class Typeface { if (familyBuilder == null) { familyBuilder = new FontFamily.Builder(fontBuilder.build()); } else { - try { - familyBuilder.addFont(fontBuilder.build()); - } catch (IllegalArgumentException e) { - if (VMRuntime.getRuntime().getTargetSdkVersion() <= VERSION_CODES.P) { - // Surpress the IllegalArgumentException for keeping the backward - // compatibility. - continue; - } - throw e; - } + familyBuilder.addFont(fontBuilder.build()); } } if (familyBuilder == null) { @@ -297,6 +286,10 @@ public class Typeface { typeface = new Typeface.CustomFallbackBuilder(family) .setStyle(bestFont.getStyle()) .build(); + } catch (IllegalArgumentException e) { + // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion + // thrown by native code and returns null. + return null; } catch (IOException e) { typeface = Typeface.DEFAULT; } diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index d74f27cca200..951970464bfe 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -310,6 +310,9 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con // Start from the back. for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) { const ApkAssets* apk_assets = *iter; + if (apk_assets->IsOverlay()) { + continue; + } auto func = [&](const StringPiece& name, FileType type) { AssetDir::FileInfo info; @@ -336,6 +339,13 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, Asset::AccessMode mode, ApkAssetsCookie* out_cookie) const { for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) { + // Prevent RRO from modifying assets and other entries accessed by file + // path. Explicitly asking for a path in a given package (denoted by a + // cookie) is still OK. + if (apk_assets_[i]->IsOverlay()) { + continue; + } + std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode); if (asset) { if (out_cookie != nullptr) { diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index db2d0382bcf6..35bbb5804df4 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -80,6 +80,10 @@ class ApkAssets { return loaded_arsc_.get(); } + inline bool IsOverlay() const { + return idmap_asset_.get() != nullptr; + } + private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java new file mode 100644 index 000000000000..6a35920e7fa2 --- /dev/null +++ b/location/java/android/location/GnssCapabilities.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2019 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. + */ + +package android.location; + +import android.annotation.IntDef; +import android.annotation.SystemApi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A container of supported GNSS chipset capabilities. + * + * @hide + */ +@SystemApi +public final class GnssCapabilities { + /** The GNSS chipset supports low power mode. */ + public static final int LOW_POWER_MODE = 0; + + /** The GNSS chipset supports blacklisting satellites. */ + public static final int SATELLITE_BLACKLIST = 1; + + /** The GNSS chipset supports geofencing. */ + public static final int GEOFENCING = 2; + + /** The GNSS chipset supports measurements.*/ + public static final int MEASUREMENTS = 3; + + /** The GNSS chipset supports navigation messages. */ + public static final int NAV_MESSAGES = 4; + + /** The GNSS chipset supports measurement corrections. */ + public static final int MEASUREMENT_CORRECTIONS = 5; + + /** The GNSS chipset supports line-of-sight satellite identification measurement corrections. */ + public static final int MEASUREMENT_CORRECTIONS_LOS_SATS = 6; + + /** The GNSS chipset supports per satellite excess-path-length measurement corrections. */ + public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 7; + + /** The GNSS chipset supports reflecting planes measurement corrections. */ + public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 8; + + private static final int MIN_CAPABILITY = 0; + private static final int MAX_CAPABILITY = MEASUREMENT_CORRECTIONS_REFLECTING_PLANE; + + /** + * GNSS capability. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + LOW_POWER_MODE, + SATELLITE_BLACKLIST, + GEOFENCING, + MEASUREMENTS, + NAV_MESSAGES, + MEASUREMENT_CORRECTIONS, + MEASUREMENT_CORRECTIONS_LOS_SATS, + MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH, + MEASUREMENT_CORRECTIONS_REFLECTING_PLANE + }) + public @interface Capability {} + + /** + * @hide + */ + public static final long INVALID_CAPABILITIES = -1; + + /** A bitmask of supported GNSS capabilities. */ + private final long mGnssCapabilities; + + static GnssCapabilities of(long gnssCapabilities) { + return new GnssCapabilities(gnssCapabilities); + } + + private GnssCapabilities(long gnssCapabilities) { + mGnssCapabilities = gnssCapabilities; + } + + /** + * Returns {@code true} if the {@code capability} is supported by the GNSS implementation. + */ + public boolean hasCapability(@Capability int capability) { + return isValidCapability(capability) && (mGnssCapabilities & (1 << capability)) != 0; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("GnssCapabilities: ("); + int capability = 0; + boolean addSeparator = false; + long gnssCapabilities = mGnssCapabilities; + while (gnssCapabilities != 0) { + if ((gnssCapabilities & 1) != 0) { + if (addSeparator) { + sb.append(' '); + } else { + addSeparator = true; + } + sb.append(toStringCapability(capability)); + } + gnssCapabilities >>= 1; + ++capability; + } + sb.append(")"); + return sb.toString(); + } + + private boolean isValidCapability(@Capability int capability) { + return capability >= MIN_CAPABILITY && capability <= MAX_CAPABILITY; + } + + private static String toStringCapability(@Capability int capability) { + switch (capability) { + case LOW_POWER_MODE: + return "LOW_POWER_MODE"; + case SATELLITE_BLACKLIST: + return "SATELLITE_BLACKLIST"; + case GEOFENCING: + return "GEOFENCING"; + case MEASUREMENTS: + return "MEASUREMENTS"; + case NAV_MESSAGES: + return "NAV_MESSAGES"; + case MEASUREMENT_CORRECTIONS: + return "MEASUREMENT_CORRECTIONS"; + case MEASUREMENT_CORRECTIONS_LOS_SATS: + return "MEASUREMENT_CORRECTIONS_LOS_SATS"; + case MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH: + return "MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH"; + case MEASUREMENT_CORRECTIONS_REFLECTING_PLANE: + return "MEASUREMENT_CORRECTIONS_REFLECTING_PLANE"; + default: + return "Unknown(" + capability + ")"; + } + } +} diff --git a/location/java/android/location/GnssMeasurementCallbackTransport.java b/location/java/android/location/GnssMeasurementCallbackTransport.java index 1188b13b7841..8cb8c0b78da1 100644 --- a/location/java/android/location/GnssMeasurementCallbackTransport.java +++ b/location/java/android/location/GnssMeasurementCallbackTransport.java @@ -63,7 +63,7 @@ class GnssMeasurementCallbackTransport measurementCorrections, getContext().getPackageName()); } - protected int getGnssCapabilities() throws RemoteException { + protected long getGnssCapabilities() throws RemoteException { return mLocationManager.getGnssCapabilities(getContext().getPackageName()); } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index c371c5fa0448..a4582b7ece92 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -66,7 +66,7 @@ interface ILocationManager boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener, in String packageName); void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections, in String packageName); - int getGnssCapabilities(in String packageName); + long getGnssCapabilities(in String packageName); void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener); boolean addGnssNavigationMessageListener( diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 01f17986d88c..edf304ca69cd 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -1986,15 +1986,19 @@ public class LocationManager { } /** - * Returns the integer capability flags of the GNSS chipset as defined in {@code - * IGnssCallback.hal} + * Returns the supported capabilities of the GNSS chipset or {@code null} if there is an error + * in obtaining the capabilities. * * @hide */ @SystemApi - public int getGnssCapabilities() { + public @Nullable GnssCapabilities getGnssCapabilities() { try { - return mGnssMeasurementCallbackTransport.getGnssCapabilities(); + long gnssCapabilities = mGnssMeasurementCallbackTransport.getGnssCapabilities(); + if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) { + return null; + } + return GnssCapabilities.of(gnssCapabilities); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 12e02e7b73cd..27499c6160d3 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -1036,6 +1036,15 @@ public final class MediaFormat { */ public static final String KEY_CA_PRIVATE_DATA = "ca-private-data"; + /** + * A key describing the maximum number of B frames between I or P frames, + * to be used by a video encoder. + * The associated value is an integer. The default value is 0, which means + * that no B frames are allowed. Note that non-zero value does not guarantee + * B frames; it's up to the encoder to decide. + */ + public static final String KEY_MAX_BFRAMES = "max-bframes"; + /* package private */ MediaFormat(@NonNull Map<String, Object> map) { mMap = map; } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 081f8a099cf5..bb8c8a6768ed 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -1,7 +1,6 @@ package com.android.settingslib.bluetooth; import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.graphics.drawable.Drawable; @@ -10,7 +9,6 @@ import android.util.Pair; import androidx.annotation.DrawableRes; import com.android.settingslib.R; -import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; import java.util.List; @@ -51,38 +49,29 @@ public class BluetoothUtils { public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context, CachedBluetoothDevice cachedDevice) { - return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */); - } - - public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context, - CachedBluetoothDevice cachedDevice, float iconScale) { BluetoothClass btClass = cachedDevice.getBtClass(); - final int level = cachedDevice.getBatteryLevel(); if (btClass != null) { switch (btClass.getMajorDeviceClass()) { case BluetoothClass.Device.Major.COMPUTER: return new Pair<>(getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_bt_laptop, level, iconScale), + com.android.internal.R.drawable.ic_bt_laptop), context.getString(R.string.bluetooth_talkback_computer)); case BluetoothClass.Device.Major.PHONE: return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_phone, level, - iconScale), + com.android.internal.R.drawable.ic_phone), context.getString(R.string.bluetooth_talkback_phone)); case BluetoothClass.Device.Major.PERIPHERAL: return new Pair<>( - getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass), - level, iconScale), + getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass)), context.getString(R.string.bluetooth_talkback_input_peripheral)); case BluetoothClass.Device.Major.IMAGING: return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_settings_print, level, - iconScale), + com.android.internal.R.drawable.ic_settings_print), context.getString(R.string.bluetooth_talkback_imaging)); default: @@ -94,38 +83,33 @@ public class BluetoothUtils { for (LocalBluetoothProfile profile : profiles) { int resId = profile.getDrawableResource(btClass); if (resId != 0) { - return new Pair<>(getBluetoothDrawable(context, resId, level, iconScale), null); + return new Pair<>(getBluetoothDrawable(context, resId), null); } } if (btClass != null) { if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_bt_headset_hfp, level, - iconScale), + com.android.internal.R.drawable.ic_bt_headset_hfp), context.getString(R.string.bluetooth_talkback_headset)); } if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_bt_headphones_a2dp, level, - iconScale), + com.android.internal.R.drawable.ic_bt_headphones_a2dp), context.getString(R.string.bluetooth_talkback_headphone)); } } return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_settings_bluetooth, level, iconScale), + com.android.internal.R.drawable.ic_settings_bluetooth), context.getString(R.string.bluetooth_talkback_bluetooth)); } - public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId, - int batteryLevel, float iconScale) { - if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { - return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel, - iconScale); - } else { - return context.getDrawable(resId); - } + /** + * Get bluetooth drawable by {@code resId} + */ + public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId) { + return context.getDrawable(resId); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java index 7a71551bb367..b713e08eb67e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java @@ -15,36 +15,55 @@ */ package com.android.settingslib.bluetooth; -import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothClass; +import android.content.Context; import android.graphics.drawable.Drawable; +import android.util.Pair; -import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; - +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class BluetoothUtilsTest { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private CachedBluetoothDevice mCachedBluetoothDevice; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + } + @Test - public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() { - final Drawable drawable = BluetoothUtils.getBluetoothDrawable( - RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop, - BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */); + public void getBtClassDrawableWithDescription_typePhone_returnPhoneDrawable() { + when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn( + BluetoothClass.Device.Major.PHONE); + final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription( + mContext, mCachedBluetoothDevice); - assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class); + verify(mContext).getDrawable(com.android.internal.R.drawable.ic_phone); } @Test - public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() { - final Drawable drawable = BluetoothUtils.getBluetoothDrawable( - RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop, - 10 /* batteryLevel */, 1 /* iconScale */); + public void getBtClassDrawableWithDescription_typeComputer_returnComputerDrawable() { + when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn( + BluetoothClass.Device.Major.COMPUTER); + final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription( + mContext, mCachedBluetoothDevice); - assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class); + verify(mContext).getDrawable(com.android.internal.R.drawable.ic_bt_laptop); } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml index 6c5c7fac3ed6..3d63b7d19c4f 100644 --- a/packages/SystemUI/res/layout/screen_record_dialog.xml +++ b/packages/SystemUI/res/layout/screen_record_dialog.xml @@ -5,26 +5,25 @@ android:clipChildren="false" android:clipToPadding="false" android:gravity="top" - android:orientation="vertical"> - - <Space - android:layout_width="match_parent" - android:layout_height="10dp"/> + android:orientation="vertical" + android:padding="@dimen/global_actions_padding" + android:background="@drawable/rounded_bg_full"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:background="@android:color/white"> + android:orientation="vertical"> <CheckBox android:id="@+id/checkbox_mic" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/screenrecord_mic_label"/> <CheckBox android:id="@+id/checkbox_taps" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/screenrecord_taps_label"/> <Button android:id="@+id/record_button" @@ -34,8 +33,4 @@ /> </LinearLayout> - <Space - android:layout_width="match_parent" - android:layout_height="10dp"/> - </LinearLayout> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index da433913bfa3..c6c2763f7801 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1069,10 +1069,10 @@ <string name="battery_saver_notification_action_text">Turn off Battery Saver</string> <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything on your screen including notifications, passwords, photos, messages and payment information.</string> + <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing the played audio and everything on your screen including notifications, passwords, photos, messages and payment information.</string> <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> to record or cast your screen?</string> + <string name="media_projection_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> to record or cast your screen and played audio?</string> <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] --> <string name="media_projection_remember_text">Don\'t show again</string> diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index c5c4b5a7e85b..78f22e0cc9e7 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -7124,6 +7124,14 @@ message MetricsEvent { // OS: Q DIALOG_FACE_REMOVE = 1693; + // FIELD - Detailed reason in screen wake. One of WAKE_REASON_* in PowerManager. + // OS: Q + FIELD_SCREEN_WAKE_REASON = 1694; + + // FIELD - Detailed reason in screen sleep. One of GO_TO_SLEEP_REASON_* in PowerManager. + // OS: Q + FIELD_SCREEN_SLEEP_REASON = 1695; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 65973121b74e..c9172683b39c 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -569,6 +569,42 @@ public final class AutofillManagerService } } + // Called by Shell command + boolean isDefaultAugmentedServiceEnabled(@UserIdInt int userId) { + enforceCallingPermissionForManagement(); + + synchronized (mLock) { + final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + return service.mAugmentedAutofillResolver.isDefaultServiceEnabled(userId); + } + } + return false; + } + + // Called by Shell command + boolean setDefaultAugmentedServiceEnabled(@UserIdInt int userId, boolean enabled) { + Slog.i(mTag, "setDefaultAugmentedServiceEnabled() for userId " + userId + ": " + enabled); + enforceCallingPermissionForManagement(); + + synchronized (mLock) { + final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + final boolean changed = service.mAugmentedAutofillResolver + .setDefaultServiceEnabled(userId, enabled); + if (changed) { + service.updateRemoteAugmentedAutofillService(); + return true; + } else { + if (debug) { + Slog.d(TAG, "setDefaultAugmentedServiceEnabled(): already " + enabled); + } + } + } + } + return false; + } + private void setLoggingLevelsLocked(boolean debug, boolean verbose) { com.android.server.autofill.Helper.sDebug = debug; android.view.autofill.Helper.sDebug = debug; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 96123468d245..dd3efa0b4afa 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -156,6 +156,7 @@ final class AutofillManagerServiceImpl /** When was {@link PruneTask} last executed? */ private long mLastPrune = 0; + // TODO(b/128911469): move to AutofillManagerService /** * Object used to set the name of the augmented autofill service. */ @@ -889,8 +890,6 @@ final class AutofillManagerServiceImpl } else { pw.println(); mInfo.dump(prefix2, pw); - pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked()); - pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked()); } pw.print(prefix); pw.print("Default component: "); pw.println(getContext() .getString(R.string.config_defaultAutofillService)); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java index c562fb1b7dde..bbe37a5df4f4 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java @@ -109,6 +109,13 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { + "implementation."); pw.println(" To reset, call with just the USER_ID argument."); pw.println(""); + pw.println(" set default-augmented-service-enabled USER_ID [true|false]"); + pw.println(" Enable / disable the default augmented autofill service for the user."); + pw.println(""); + pw.println(" get default-augmented-service-enabled USER_ID"); + pw.println(" Checks whether the default augmented autofill service is enabled for " + + "the user."); + pw.println(""); pw.println(" list sessions [--user USER_ID]"); pw.println(" Lists all pending sessions."); pw.println(""); @@ -136,6 +143,8 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { return getFullScreenMode(pw); case "bind-instant-service-allowed": return getBindInstantService(pw); + case "default-augmented-service-enabled": + return getDefaultAugmentedServiceEnabled(pw); default: pw.println("Invalid set: " + what); return -1; @@ -158,6 +167,8 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { return setBindInstantService(pw); case "temporary-augmented-service": return setTemporaryAugmentedService(pw); + case "default-augmented-service-enabled": + return setDefaultAugmentedServiceEnabled(pw); default: pw.println("Invalid set: " + what); return -1; @@ -314,6 +325,23 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { return 0; } + private int getDefaultAugmentedServiceEnabled(PrintWriter pw) { + final int userId = getNextIntArgRequired(); + final boolean enabled = mService.isDefaultAugmentedServiceEnabled(userId); + pw.println(enabled); + return 0; + } + + private int setDefaultAugmentedServiceEnabled(PrintWriter pw) { + final int userId = getNextIntArgRequired(); + final boolean enabled = Boolean.parseBoolean(getNextArgRequired()); + final boolean changed = mService.setDefaultAugmentedServiceEnabled(userId, enabled); + if (!changed) { + pw.println("already " + enabled); + } + return 0; + } + private int requestDestroy(PrintWriter pw) { if (!isNextArgSessions(pw)) { return -1; diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java index 86ad52d9a42b..fc9754a2b0f5 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java @@ -114,7 +114,7 @@ public final class ContentCaptureManagerServiceShellCommand extends ShellCommand case "temporary-service": return setTemporaryService(pw); case "default-service-enabled": - return setDefaultServiceEnabled(); + return setDefaultServiceEnabled(pw); default: pw.println("Invalid set: " + what); return -1; @@ -159,10 +159,13 @@ public final class ContentCaptureManagerServiceShellCommand extends ShellCommand return 0; } - private int setDefaultServiceEnabled() { + private int setDefaultServiceEnabled(PrintWriter pw) { final int userId = getNextIntArgRequired(); - final boolean enabled = Boolean.parseBoolean(getNextArg()); - mService.setDefaultServiceEnabled(userId, enabled); + final boolean enabled = Boolean.parseBoolean(getNextArgRequired()); + final boolean changed = mService.setDefaultServiceEnabled(userId, enabled); + if (!changed) { + pw.println("already " + enabled); + } return 0; } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index c423f9c87d29..d7d97b39959f 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -27,12 +27,10 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTE import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE; -import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; -import android.app.AppGlobals; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.content.ComponentName; @@ -44,12 +42,12 @@ import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; -import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.ActivityEvent.ActivityEventType; import android.service.contentcapture.ContentCaptureService; +import android.service.contentcapture.ContentCaptureServiceInfo; import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.ArrayMap; @@ -107,6 +105,9 @@ final class ContentCapturePerUserService @GuardedBy("mLock") private boolean mZombie; + @GuardedBy("mLock") + private ContentCaptureServiceInfo mInfo; + // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's ContentCapturePerUserService(@NonNull ContentCaptureManagerService master, @@ -144,33 +145,9 @@ final class ContentCapturePerUserService @Override // from PerUserSystemService protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) throws NameNotFoundException { - - int flags = PackageManager.GET_META_DATA; - final boolean isTemp = isTemporaryServiceSetLocked(); - if (!isTemp) { - flags |= PackageManager.MATCH_SYSTEM_ONLY; - } - - ServiceInfo si; - try { - si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags, mUserId); - } catch (RemoteException e) { - Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e); - return null; - } - if (si == null) { - Slog.w(TAG, "Could not get serviceInfo for " + (isTemp ? " (temp)" : "(default system)") - + " " + serviceComponent.flattenToShortString()); - return null; - } - if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) { - Slog.w(TAG, "ContentCaptureService from '" + si.packageName - + "' does not require permission " - + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); - throw new SecurityException("Service does not require permission " - + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); - } - return si; + mInfo = new ContentCaptureServiceInfo(getContext(), serviceComponent, + isTemporaryServiceSetLocked(), mUserId); + return mInfo.getServiceInfo(); } @Override // from PerUserSystemService @@ -490,9 +467,16 @@ final class ContentCapturePerUserService protected void dumpLocked(String prefix, PrintWriter pw) { super.dumpLocked(prefix, pw); + final String prefix2 = prefix + " "; + pw.print(prefix); pw.print("Service Info: "); + if (mInfo == null) { + pw.println("N/A"); + } else { + pw.println(); + mInfo.dump(prefix2, pw); + } pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie); - final String prefix2 = prefix + " "; if (mRemoteService != null) { pw.print(prefix); pw.println("remote service:"); mRemoteService.dump(prefix2, pw); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 6ef5b547a353..ceeb53980685 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -2943,7 +2943,7 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public int getGnssCapabilities(String packageName) { + public long getGnssCapabilities(String packageName) { mContext.enforceCallingPermission( android.Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to obtain GNSS chipset capabilities."); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 19b0bf795393..8cb1ec73a00d 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -208,6 +208,13 @@ class StorageManagerService extends IStorageManager.Stub private static final boolean ENABLE_LEGACY_GREYLIST = SystemProperties .getBoolean(StorageManager.PROP_LEGACY_GREYLIST, true); + /** + * If {@code 1}, enables the isolated storage feature. If {@code -1}, + * disables the isolated storage feature. If {@code 0}, uses the default + * value from the build system. + */ + private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; + public static class Lifecycle extends SystemService { private StorageManagerService mStorageManagerService; @@ -797,7 +804,7 @@ class StorageManagerService extends IStorageManager.Stub } }); // For now, simply clone property when it changes - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE, + DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE, mContext.getMainExecutor(), (namespace, name, value) -> { refreshIsolatedStorageSettings(); }); @@ -837,8 +844,7 @@ class StorageManagerService extends IStorageManager.Stub // Always copy value from newer DeviceConfig location Settings.Global.putString(mResolver, Settings.Global.ISOLATED_STORAGE_REMOTE, - DeviceConfig.getProperty(DeviceConfig.Storage.NAMESPACE, - DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED)); + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE, ISOLATED_STORAGE_ENABLED)); final int local = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ISOLATED_STORAGE_LOCAL, 0); diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 4e0380d37820..42a7a5c18a48 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -113,6 +113,11 @@ public class AttentionManagerService extends SystemService { cancelAndUnbindLocked(peekUserStateLocked(userId)); } + /** Returns {@code true} if attention service is configured on this device. */ + public static boolean isServiceConfigured(Context context) { + return !TextUtils.isEmpty(getServiceConfig(context)); + } + /** Resolves and sets up the attention service if it had not been done yet. */ private boolean isServiceAvailable() { if (mComponentName == null) { @@ -285,6 +290,10 @@ public class AttentionManagerService extends SystemService { return mUserStates.get(userId); } + private static String getServiceConfig(Context context) { + return context.getString(R.string.config_defaultAttentionService); + } + /** * Provides attention service component name at runtime, making sure it's provided by the * system. @@ -293,9 +302,7 @@ public class AttentionManagerService extends SystemService { final String flag = DeviceConfig.getProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, COMPONENT_NAME); - final String componentNameString = flag != null ? flag : context.getString( - R.string.config_defaultAttentionService); - + final String componentNameString = flag != null ? flag : getServiceConfig(context); if (TextUtils.isEmpty(componentNameString)) { return null; } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index f313e1d48c53..516844d85484 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -628,6 +628,9 @@ public class BiometricService extends SystemService { null /* description */); // Then give it the bundle to do magic behavior.. intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle); + // Create a new task with this activity located at the root. + intent.setFlags( + Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT); getContext().startActivityAsUser(intent, UserHandle.CURRENT); }); return; diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 45567e5a34cb..ed420b73e79b 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -1417,7 +1417,7 @@ public final class ColorDisplayService extends SystemService { mCurrentColorTemperature = cct; // Adapt the display's nominal white point to match the requested CCT value - mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct); + mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct); mChromaticAdaptationMatrix = ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD, diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java index 3c27bf240570..430203de8268 100644 --- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java @@ -332,21 +332,31 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem * with the test results. * * @throws SecurityException if caller is not allowed to manage this service's settings. + * + * @return whether the enabled state changed. */ - public final void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) { + public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) { Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled); enforceCallingPermissionForManagement(); synchronized (mLock) { + final boolean changed = mServiceNameResolver.setDefaultServiceEnabled(userId, enabled); + if (!changed) { + if (verbose) { + Slog.v(mTag, "setDefaultServiceEnabled(" + userId + "): already " + enabled); + } + return false; + } + final S oldService = peekServiceForUserLocked(userId); if (oldService != null) { oldService.removeSelfFromCacheLocked(); } - mServiceNameResolver.setDefaultServiceEnabled(userId, enabled); // Must update the service on cache so its initialization code is triggered updateCachedServiceLocked(userId); } + return true; } /** diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java index cd9ebcda009c..ac07e9d6b0b7 100644 --- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java @@ -327,6 +327,10 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst @GuardedBy("mLock") protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { pw.print(prefix); pw.print("User: "); pw.println(mUserId); + if (mServiceInfo != null) { + pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked()); + pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked()); + } if (mMaster.mServiceNameResolver != null) { pw.print(prefix); pw.print("Name resolver: "); mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println(); diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java index 1b237949a543..d20481331e56 100644 --- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java @@ -174,23 +174,35 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR } @Override - public void setDefaultServiceEnabled(int userId, boolean enabled) { + public boolean setDefaultServiceEnabled(int userId, boolean enabled) { synchronized (mLock) { + final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId); + if (currentlyEnabled == enabled) { + Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled); + return false; + } if (enabled) { + Slog.i(TAG, "disabling default service for user " + userId); mDefaultServicesDisabled.removeAt(userId); } else { + Slog.i(TAG, "enabling default service for user " + userId); mDefaultServicesDisabled.put(userId, true); } } + return true; } @Override public boolean isDefaultServiceEnabled(int userId) { synchronized (mLock) { - return !mDefaultServicesDisabled.get(userId); + return isDefaultServiceEnabledLocked(userId); } } + private boolean isDefaultServiceEnabledLocked(int userId) { + return !mDefaultServicesDisabled.get(userId); + } + @Override public String toString() { return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]"; diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java index 5b60413eefad..8c348ebbfcd4 100644 --- a/services/core/java/com/android/server/infra/ServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java @@ -115,11 +115,13 @@ public interface ServiceNameResolver { * * @param userId user handle * @param enabled whether the default service should be used when the temporary service is not - * set + * set. If the service enabled state is already that value, the command is ignored and this + * method return {@code false}. * + * @return whether the enabled state changed. * @throws UnsupportedOperationException if not implemented. */ - default void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) { + default boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) { throw new UnsupportedOperationException("changing default service not supported"); } diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java index a9126c0caa74..031b5ce3d5b9 100644 --- a/services/core/java/com/android/server/pm/PackageKeySetData.java +++ b/services/core/java/com/android/server/pm/PackageKeySetData.java @@ -107,10 +107,7 @@ public class PackageKeySetData { } protected void removeAllDefinedKeySets() { - final int aliasSize = mKeySetAliases.size(); - for (int i = 0; i < aliasSize; i++) { - mKeySetAliases.removeAt(i); - } + mKeySetAliases.erase(); } protected boolean isUsingDefinedKeySets() { diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index eced165bf257..9782648efb6b 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -99,6 +99,7 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_ICON_RES_ID = "icon-res"; private static final String ATTR_ICON_RES_NAME = "icon-resname"; private static final String ATTR_BITMAP_PATH = "bitmap-path"; + private static final String ATTR_LOCUS_ID = "locus-id"; private static final String ATTR_PERSON_NAME = "name"; private static final String ATTR_PERSON_URI = "uri"; @@ -1473,6 +1474,10 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_DISABLED_REASON, si.getDisabledReason()); ShortcutService.writeAttr(out, ATTR_TIMESTAMP, si.getLastChangedTimestamp()); + final LocusId locusId = si.getLocusId(); + if (locusId != null) { + ShortcutService.writeAttr(out, ATTR_LOCUS_ID, si.getLocusId().getId()); + } if (forBackup) { // Don't write icon information. Also drop the dynamic flag. @@ -1612,6 +1617,7 @@ class ShortcutPackage extends ShortcutPackageItem { int iconResId; String iconResName; String bitmapPath; + final String locusIdString; int backupVersionCode; ArraySet<String> categories = null; ArrayList<Person> persons = new ArrayList<>(); @@ -1638,6 +1644,7 @@ class ShortcutPackage extends ShortcutPackageItem { iconResId = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES_ID); iconResName = ShortcutService.parseStringAttribute(parser, ATTR_ICON_RES_NAME); bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH); + locusIdString = ShortcutService.parseStringAttribute(parser, ATTR_LOCUS_ID); final int outerDepth = parser.getDepth(); int type; @@ -1703,7 +1710,7 @@ class ShortcutPackage extends ShortcutPackageItem { flags |= ShortcutInfo.FLAG_SHADOW; } - LocusId locusId = null; // LocusId is not set on XML. + final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString); return new ShortcutInfo( userId, id, packageName, activityComponent, /* icon= */ null, diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index 406cbc10a8aa..701e5af01290 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -269,7 +269,7 @@ public class AttentionDetector { */ @VisibleForTesting boolean isAttentionServiceSupported() { - return mAttentionManager.isAttentionServiceSupported(); + return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported(); } public void dump(PrintWriter pw) { diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 1a82858147f4..b81d969a1bb2 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -486,6 +486,8 @@ public class Notifier { log.setType(MetricsEvent.TYPE_OPEN); log.setSubtype(why); log.setLatency(interactiveChangeLatency); + log.addTaggedData( + MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason); MetricsLogger.action(log); EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency); mPolicy.finishedWakingUp(why); @@ -513,6 +515,8 @@ public class Notifier { log.setType(MetricsEvent.TYPE_CLOSE); log.setSubtype(why); log.setLatency(interactiveChangeLatency); + log.addTaggedData( + MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason); MetricsLogger.action(log); EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency); mPolicy.finishedGoingToSleep(why); diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 1e2dad915e85..d6327494a24d 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -44,6 +44,7 @@ import android.os.HandlerThread; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.DeviceConfig; import android.util.IntArray; import android.util.Log; @@ -455,11 +456,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED); - // TODO: This call emits the warning "Calling a method in the - // system process without a qualified user". Fix that. - // TODO: Limit this to receivers holding the - // MANAGE_ROLLBACKS or TEST_MANAGE_ROLLBACKS permissions? - mContext.sendBroadcast(broadcast); + mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM, + Manifest.permission.MANAGE_ROLLBACKS); }); } ); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index f63269571fc0..75e34fb0d453 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; +import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH; import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; @@ -638,6 +639,39 @@ public class AppTransitionController { return transit; } + /** + * Identifies whether the current transition occurs within a single task or not. This is used + * to determine whether animations should be clipped to the task bounds instead of stack bounds. + */ + @VisibleForTesting + boolean isTransitWithinTask(int transit, Task task) { + if (task == null + || !mDisplayContent.mChangingApps.isEmpty()) { + // if there is no task, then we can't constrain to the task. + // if anything is changing, it can animate outside its task. + return false; + } + if (!(transit == TRANSIT_ACTIVITY_OPEN + || transit == TRANSIT_ACTIVITY_CLOSE + || transit == TRANSIT_ACTIVITY_RELAUNCH)) { + // only activity-level transitions will be within-task. + return false; + } + // check that all components are in the task. + for (AppWindowToken activity : mDisplayContent.mOpeningApps) { + Task activityTask = activity.getTask(); + if (activityTask != task) { + return false; + } + } + for (AppWindowToken activity : mDisplayContent.mClosingApps) { + if (activity.getTask() != task) { + return false; + } + } + return true; + } + private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) { for (int i = apps.size() - 1; i >= 0; i--) { if (apps.valueAt(i).windowsCanBeWallpaperTarget()) { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index ea3a7d5ca3b2..3f29181f0215 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -2705,16 +2705,21 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // If the animation needs to be cropped then an animation bounds layer is created as a child // of the pinned stack or animation layer. The leash is then reparented to this new layer. if (mNeedsAnimationBoundsLayer) { - final TaskStack stack = getStack(); - if (stack == null) { - return; + mTmpRect.setEmpty(); + final Task task = getTask(); + if (getDisplayContent().mAppTransitionController.isTransitWithinTask( + getTransit(), task)) { + task.getBounds(mTmpRect); + } else { + final TaskStack stack = getStack(); + if (stack == null) { + return; + } + // Set clip rect to stack bounds. + stack.getBounds(mTmpRect); } mAnimationBoundsLayer = createAnimationBoundsLayer(t); - // Set clip rect to stack bounds. - mTmpRect.setEmpty(); - stack.getBounds(mTmpRect); - // Crop to stack bounds. t.setWindowCrop(mAnimationBoundsLayer, mTmpRect); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b00cafdccf11..bec72f5686df 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -130,6 +130,7 @@ import static com.android.server.wm.WindowManagerService.logSurface; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; +import static com.android.server.wm.utils.RegionUtils.rectListToRegion; import android.animation.AnimationHandler; import android.annotation.CallSuper; @@ -153,6 +154,7 @@ import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -165,6 +167,7 @@ import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Gravity; +import android.view.ISystemGestureExclusionListener; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputWindowHandle; @@ -312,6 +315,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private DisplayRotation mDisplayRotation; DisplayFrames mDisplayFrames; + private final RemoteCallbackList<ISystemGestureExclusionListener> + mSystemGestureExclusionListeners = new RemoteCallbackList<>(); + private final Region mSystemGestureExclusion = new Region(); + /** * For default display it contains real metrics, empty for others. * @see WindowManagerService#createWatermarkInTransaction() @@ -2818,6 +2825,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mWallpaperController.dump(pw, " "); pw.println(); + pw.print("mSystemGestureExclusion="); + if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) { + pw.println(mSystemGestureExclusion); + } else { + pw.println("<no lstnrs>"); + } + + pw.println(); pw.println(prefix + "Application tokens in top down Z order:"); for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); @@ -4951,6 +4966,100 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } /** + * Updates the display's system gesture exclusion. + * + * @return true, if the exclusion changed. + */ + boolean updateSystemGestureExclusion() { + if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 0) { + // No one's interested anyways. + return false; + } + + final Region systemGestureExclusion = calculateSystemGestureExclusion(); + try { + if (mSystemGestureExclusion.equals(systemGestureExclusion)) { + return false; + } + mSystemGestureExclusion.set(systemGestureExclusion); + for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) { + try { + mSystemGestureExclusionListeners.getBroadcastItem(i) + .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e); + } + } + mSystemGestureExclusionListeners.finishBroadcast(); + return true; + } finally { + systemGestureExclusion.recycle(); + } + } + + @VisibleForTesting + Region calculateSystemGestureExclusion() { + final Region global = Region.obtain(); + final Region touchableRegion = Region.obtain(); + final Region local = Region.obtain(); + + // Traverse all windows bottom up to assemble the gesture exclusion rects. + // For each window, we only take the rects that fall within its touchable region. + forAllWindows(w -> { + if (w.cantReceiveTouchInput() || !w.isVisible() + || (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0) { + return; + } + final boolean modal = + (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; + + // Only keep the exclusion zones from the windows behind where the current window + // isn't touchable. + w.getTouchableRegion(touchableRegion); + global.op(touchableRegion, Op.DIFFERENCE); + + rectListToRegion(w.getSystemGestureExclusion(), local); + + // Transform to display coordinates + local.scale(w.mGlobalScale); + final Rect frame = w.getWindowFrames().mFrame; + local.translate(frame.left, frame.top); + + // A window can only exclude system gestures where it is actually touchable + local.op(touchableRegion, Op.INTERSECT); + + global.op(local, Op.UNION); + }, false /* topToBottom */); + local.recycle(); + touchableRegion.recycle(); + return global; + } + + void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) { + mSystemGestureExclusionListeners.register(listener); + final boolean changed; + if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 1) { + changed = updateSystemGestureExclusion(); + } else { + changed = false; + } + + if (!changed) { + // If updateSystemGestureExclusion changed the exclusion, it will already have + // notified the listener. Otherwise, we'll do it here. + try { + listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e); + } + } + } + + void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener) { + mSystemGestureExclusionListeners.unregister(listener); + } + + /** * Create a portal window handle for input. This window transports any touch to the display * indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window. * diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 8f4e8422581b..ed5f6658197b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -682,6 +682,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Finally update all input windows now that the window changes have stabilized. forAllDisplays(dc -> { dc.getInputMonitor().updateInputWindowsLw(true /*force*/); + dc.updateSystemGestureExclusion(); }); mWmService.setHoldScreenLocked(mHoldScreen); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index dc8c7b79feef..9b634f959fca 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -57,6 +57,7 @@ import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.function.BiConsumer; @@ -314,6 +315,16 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } } + @Override + public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) { + long ident = Binder.clearCallingIdentity(); + try { + mService.reportSystemGestureExclusionChanged(this, window, exclusionRects); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void actionOnWallpaper(IBinder window, BiConsumer<WallpaperController, WindowState> action) { final WindowState windowState = mService.windowForClientLocked(this, window, true); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4a9d798fda3c..7751560203e7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -202,6 +202,7 @@ import android.view.IOnKeyguardExitResult; import android.view.IPinnedStackListener; import android.view.IRecentsAnimationRunner; import android.view.IRotationWatcher; +import android.view.ISystemGestureExclusionListener; import android.view.IWallpaperVisibilityListener; import android.view.IWindow; import android.view.IWindowId; @@ -274,6 +275,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub @@ -3817,6 +3819,42 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId) { + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("Trying to register visibility event " + + "for invalid display: " + displayId); + } + displayContent.registerSystemGestureExclusionListener(listener); + } + } + + @Override + public void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId) { + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("Trying to register visibility event " + + "for invalid display: " + displayId); + } + displayContent.unregisterSystemGestureExclusionListener(listener); + } + } + + void reportSystemGestureExclusionChanged(Session session, IWindow window, + List<Rect> exclusionRects) { + synchronized (mGlobalLock) { + final WindowState win = windowForClientLocked(session, window, true); + if (win.setSystemGestureExclusion(exclusionRects)) { + win.getDisplayContent().updateSystemGestureExclusion(); + } + } + } + + @Override public void registerDisplayFoldListener(IDisplayFoldListener listener) { mPolicy.registerDisplayFoldListener(listener); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ee445d836214..600178fa3276 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -205,6 +205,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.function.Predicate; /** A window in the window manager. */ @@ -363,6 +364,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private final Rect mInsetFrame = new Rect(); + /** + * List of rects where system gestures should be ignored. + * + * Coordinates are relative to the window's position. + */ + private final List<Rect> mExclusionRects = new ArrayList<>(); + // If a window showing a wallpaper: the requested offset for the // wallpaper; if a wallpaper window: the currently applied offset. float mWallpaperX = -1; @@ -612,6 +620,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + List<Rect> getSystemGestureExclusion() { + return mExclusionRects; + } + + /** + * Sets the system gesture exclusion rects. + * + * @return {@code true} if anything changed + */ + boolean setSystemGestureExclusion(List<Rect> exclusionRects) { + if (mExclusionRects.equals(exclusionRects)) { + return false; + } + mExclusionRects.clear(); + mExclusionRects.addAll(exclusionRects); + return true; + } + interface PowerManagerWrapper { void wakeUp(long time, @WakeReason int reason, String details); diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java new file mode 100644 index 000000000000..1458440f7b81 --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 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. + */ + +package com.android.server.wm.utils; + +import android.graphics.Rect; +import android.graphics.Region; + +import java.util.List; + +/** + * Utility methods to handle Regions. + */ +public class RegionUtils { + + private RegionUtils() {} + + + /** + * Converts a list of rects into a {@code Region}. + * + * @param rects the list of rects to convert + * @param outRegion the Region to set to the list of rects + */ + public static void rectListToRegion(List<Rect> rects, Region outRegion) { + outRegion.setEmpty(); + final int n = rects.size(); + for (int i = 0; i < n; i++) { + outRegion.union(rects.get(i)); + } + } +} diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index a4955f07801a..a6e9fdde7735 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -119,7 +119,6 @@ using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V1_0::IAGnssRilCallback; using android::hardware::gnss::V1_0::IGnssBatching; using android::hardware::gnss::V1_0::IGnssBatchingCallback; -using android::hardware::gnss::V1_0::IGnssDebug; using android::hardware::gnss::V1_0::IGnssGeofenceCallback; using android::hardware::gnss::V1_0::IGnssGeofencing; using android::hardware::gnss::V1_0::IGnssNavigationMessage; @@ -143,9 +142,12 @@ using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation; using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss; using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss; using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss; +using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback; using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration; using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; +using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug; +using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug; using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; @@ -191,7 +193,8 @@ sp<IGnssGeofencing> gnssGeofencingIface = nullptr; sp<IAGnss_V1_0> agnssIface = nullptr; sp<IAGnss_V2_0> agnssIface_V2_0 = nullptr; sp<IGnssBatching> gnssBatchingIface = nullptr; -sp<IGnssDebug> gnssDebugIface = nullptr; +sp<IGnssDebug_V1_0> gnssDebugIface = nullptr; +sp<IGnssDebug_V2_0> gnssDebugIface_V2_0 = nullptr; sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr; sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr; sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr; @@ -548,7 +551,9 @@ static GnssLocation_V2_0 createGnssLocation_V2_0( struct GnssCallback : public IGnssCallback { Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override; Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override; - Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; + Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override { + return gnssSvStatusCbImpl(svStatus); + } Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override; Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override; Return<void> gnssAcquireWakelockCb() override; @@ -566,16 +571,47 @@ struct GnssCallback : public IGnssCallback { override; Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override; Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override; - - // Templated implementation for gnnsLocationCb and gnnsLocationCb_2_0. - template <class T> - Return<void> gnssLocationCbImpl(const T& location); + Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) override { + return gnssSvStatusCbImpl(svInfoList); + } Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags); // TODO: Reconsider allocation cost vs threadsafety on these statics static const char* sNmeaString; static size_t sNmeaStringLength; +private: + template<class T> + Return<void> gnssLocationCbImpl(const T& location); + + template<class T> + Return<void> gnssSvStatusCbImpl(const T& svStatus); + + uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) { + return svStatus.numSvs; + } + + uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) { + return svInfoList.size(); + } + + const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex( + const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) { + return svStatus.gnssSvList.data()[i]; + } + + const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex( + const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) { + return svInfoList[i].v1_0; + } + + uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) { + return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation); + } + + uint32_t getConstellationType(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) { + return static_cast<uint32_t>(svInfoList[i].constellation); + } }; Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { @@ -623,10 +659,11 @@ Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue sta return Void(); } -Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) { +template<class T> +Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) { JNIEnv* env = getJniEnv(); - uint32_t listSize = svStatus.numSvs; + uint32_t listSize = getGnssSvInfoListSize(svStatus); if (listSize > static_cast<uint32_t>( android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) { ALOGD("Too many satellites %u. Clamps to %u.", listSize, @@ -655,9 +692,9 @@ Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svS CONSTELLATION_TYPE_SHIFT_WIDTH = 4 }; - const IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList.data()[i]; + const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i); svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) | - (static_cast<uint32_t>(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) | + (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) | static_cast<uint32_t>(info.svFlag); cn0s[i] = info.cN0Dbhz; elev[i] = info.elevationDegrees; @@ -1079,6 +1116,9 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated. SET(State, static_cast<int32_t>(measurement_V2_0->state)); + + // Overwrite with v2_0.constellation since v2_0->v1_1->v1_0.constellation is deprecated. + SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation)); } jobject GnssMeasurementCallback::translateGnssClock( @@ -1656,11 +1696,21 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass } } - auto gnssDebug = gnssHal->getExtensionGnssDebug(); - if (!gnssDebug.isOk()) { - ALOGD("Unable to get a handle to GnssDebug"); + if (gnssHal_V2_0 != nullptr) { + auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0(); + if (!gnssDebug.isOk()) { + ALOGD("Unable to get a handle to GnssDebug_V2_0"); + } else { + gnssDebugIface_V2_0 = gnssDebug; + gnssDebugIface = gnssDebugIface_V2_0; + } } else { - gnssDebugIface = gnssDebug; + auto gnssDebug = gnssHal->getExtensionGnssDebug(); + if (!gnssDebug.isOk()) { + ALOGD("Unable to get a handle to GnssDebug"); + } else { + gnssDebugIface = gnssDebug; + } } auto gnssNi = gnssHal->getExtensionGnssNi(); @@ -2189,6 +2239,76 @@ static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* en gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response)); } +const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) { + return satelliteDataArray[i]; +} + +const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) { + return satelliteDataArray[i].v1_0; +} + +template<class T> +uint32_t getConstellationType(const hidl_vec<T>& satelliteDataArray, size_t i) { + return static_cast<uint32_t>(satelliteDataArray[i].constellation); +} + +template<class T> +static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, const T& data) { + internalState << "Gnss Location Data:: "; + if (!data.position.valid) { + internalState << "not valid"; + } else { + internalState << "LatitudeDegrees: " << data.position.latitudeDegrees + << ", LongitudeDegrees: " << data.position.longitudeDegrees + << ", altitudeMeters: " << data.position.altitudeMeters + << ", speedMetersPerSecond: " << data.position.speedMetersPerSec + << ", bearingDegrees: " << data.position.bearingDegrees + << ", horizontalAccuracyMeters: " + << data.position.horizontalAccuracyMeters + << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters + << ", speedAccuracyMetersPerSecond: " + << data.position.speedAccuracyMetersPerSecond + << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees + << ", ageSeconds: " << data.position.ageSeconds; + } + internalState << std::endl; + + internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate + << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs + << ", frequencyUncertaintyNsPerSec: " + << data.time.frequencyUncertaintyNsPerSec << std::endl; + + if (data.satelliteDataArray.size() != 0) { + internalState << "Satellite Data for " << data.satelliteDataArray.size() + << " satellites:: " << std::endl; + } + + internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; " + << "ephType: 0=Eph, 1=Alm, 2=Unk; " + << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; " + << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl; + for (size_t i = 0; i < data.satelliteDataArray.size(); i++) { + IGnssDebug_V1_0::SatelliteData satelliteData = + getSatelliteData(data.satelliteDataArray, i); + internalState << "constell: " + << getConstellationType(data.satelliteDataArray, i) + << ", svid: " << std::setw(3) << satelliteData.svid + << ", serverPredAvail: " + << satelliteData.serverPredictionIsAvailable + << ", serverPredAgeSec: " << std::setw(7) + << satelliteData.serverPredictionAgeSeconds + << ", ephType: " + << static_cast<uint32_t>(satelliteData.ephemerisType) + << ", ephSource: " + << static_cast<uint32_t>(satelliteData.ephemerisSource) + << ", ephHealth: " + << static_cast<uint32_t>(satelliteData.ephemerisHealth) + << ", ephAgeSec: " << std::setw(7) + << satelliteData.ephemerisAgeSeconds << std::endl; + } + return (jstring) env->NewStringUTF(internalState.str().c_str()); +} + static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env, jobject /* obj */) { jstring result = nullptr; @@ -2200,65 +2320,19 @@ static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* if (gnssDebugIface == nullptr) { internalState << "Gnss Debug Interface not available" << std::endl; + } else if (gnssDebugIface_V2_0 != nullptr) { + IGnssDebug_V2_0::DebugData data; + gnssDebugIface_V2_0->getDebugData_2_0([&data](const IGnssDebug_V2_0::DebugData& debugData) { + data = debugData; + }); + result = parseDebugData(env, internalState, data); } else { - IGnssDebug::DebugData data; - gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) { + IGnssDebug_V1_0::DebugData data; + gnssDebugIface->getDebugData([&data](const IGnssDebug_V1_0::DebugData& debugData) { data = debugData; }); - - internalState << "Gnss Location Data:: "; - if (!data.position.valid) { - internalState << "not valid"; - } else { - internalState << "LatitudeDegrees: " << data.position.latitudeDegrees - << ", LongitudeDegrees: " << data.position.longitudeDegrees - << ", altitudeMeters: " << data.position.altitudeMeters - << ", speedMetersPerSecond: " << data.position.speedMetersPerSec - << ", bearingDegrees: " << data.position.bearingDegrees - << ", horizontalAccuracyMeters: " - << data.position.horizontalAccuracyMeters - << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters - << ", speedAccuracyMetersPerSecond: " - << data.position.speedAccuracyMetersPerSecond - << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees - << ", ageSeconds: " << data.position.ageSeconds; - } - internalState << std::endl; - - internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate - << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs - << ", frequencyUncertaintyNsPerSec: " - << data.time.frequencyUncertaintyNsPerSec << std::endl; - - if (data.satelliteDataArray.size() != 0) { - internalState << "Satellite Data for " << data.satelliteDataArray.size() - << " satellites:: " << std::endl; - } - - internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; " - << "ephType: 0=Eph, 1=Alm, 2=Unk; " - << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; " - << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl; - for (size_t i = 0; i < data.satelliteDataArray.size(); i++) { - internalState << "constell: " - << static_cast<uint32_t>(data.satelliteDataArray[i].constellation) - << ", svid: " << std::setw(3) << data.satelliteDataArray[i].svid - << ", serverPredAvail: " - << data.satelliteDataArray[i].serverPredictionIsAvailable - << ", serverPredAgeSec: " << std::setw(7) - << data.satelliteDataArray[i].serverPredictionAgeSeconds - << ", ephType: " - << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisType) - << ", ephSource: " - << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisSource) - << ", ephHealth: " - << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisHealth) - << ", ephAgeSec: " << std::setw(7) - << data.satelliteDataArray[i].ephemerisAgeSeconds << std::endl; - } + result = parseDebugData(env, internalState, data); } - - result = env->NewStringUTF(internalState.str().c_str()); return result; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 39af565d156f..419f52cff578 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1230,6 +1230,7 @@ public final class SystemServer { } startContentCaptureService(context); + startAttentionService(context); // App prediction manager service traceBeginAndSlog("StartAppPredictionService"); @@ -1284,10 +1285,6 @@ public final class SystemServer { traceEnd(); } - traceBeginAndSlog("StartAttentionManagerService"); - mSystemServiceManager.startService(AttentionManagerService.class); - traceEnd(); - traceBeginAndSlog("StartNetworkScoreService"); mSystemServiceManager.startService(NetworkScoreService.Lifecycle.class); traceEnd(); @@ -2260,6 +2257,17 @@ public final class SystemServer { traceEnd(); } + private void startAttentionService(@NonNull Context context) { + if (!AttentionManagerService.isServiceConfigured(context)) { + Slog.d(TAG, "AttentionService is not configured on this device"); + return; + } + + traceBeginAndSlog("StartAttentionManagerService"); + mSystemServiceManager.startService(AttentionManagerService.class); + traceEnd(); + } + static final void startSystemUi(Context context, WindowManagerService windowManager) { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.android.systemui", diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index cd095a5fa6ff..fa1bcaccd786 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -35,6 +35,7 @@ import android.app.ActivityManager; import android.app.Person; import android.content.ComponentName; import android.content.Intent; +import android.content.LocusId; import android.content.pm.ShortcutInfo; import android.content.res.Resources; import android.graphics.BitmapFactory; @@ -895,6 +896,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setRank(123) .setExtras(pb) + .setLocusId(new LocusId("1.2.3.4.5")) .build(); sorig.setTimestamp(mInjectedCurrentTimeMillis); @@ -906,6 +908,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setPersons(list(makePerson("person1", "personKey1", "personUri1"), makePerson("person2", "personKey2", "personUri2")).toArray(new Person[2])) .setRank(456) + .setLocusId(new LocusId("6.7.8.9")) .build(); sorig2.setTimestamp(mInjectedCurrentTimeMillis); @@ -946,6 +949,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("personUri", si.getPersons()[0].getUri()); assertEquals(0, si.getRank()); assertEquals(1, si.getExtras().getInt("k")); + assertEquals("1.2.3.4.5", si.getLocusId().getId()); assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags()); @@ -959,6 +963,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(1, si.getRank()); assertEquals(2, si.getPersons().length); assertEquals("personUri2", si.getPersons()[1].getUri()); + assertEquals("6.7.8.9", si.getLocusId().getId()); dumpUserFile(USER_10); } diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java index a2f1f01b689f..a1a58b49329f 100644 --- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java @@ -105,6 +105,13 @@ public class AttentionDetectorTest extends AndroidTestCase { } @Test + public void testOnUserActivity_doesntCrashIfNoAttentionService() { + mAttentionManagerInternal = null; + registerAttention(); + // Does not crash. + } + + @Test public void onUserActivity_ignoresWhiteListedActivityTypes() { for (int i = 0; i < NUM_USER_ACTIVITY_TYPES; i++) { int result = mAttentionDetector.onUserActivity(SystemClock.uptimeMillis(), i); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 81133d1052ec..9bd993070939 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -17,12 +17,16 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; import static android.view.WindowManager.TRANSIT_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_TASK_OPEN; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import android.view.WindowManager; @@ -95,4 +99,24 @@ public class AppTransitionControllerTest extends WindowTestsBase { TRANSIT_TASK_CHANGE_WINDOWING_MODE)); } } + + @Test + public void testTransitWithinTask() { + synchronized (mWm.mGlobalLock) { + final AppWindowToken opening = createAppWindowToken(mDisplayContent, + WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); + opening.setFillsParent(false); + final AppWindowToken closing = createAppWindowToken(mDisplayContent, + WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); + closing.setFillsParent(false); + Task task = opening.getTask(); + mDisplayContent.mOpeningApps.add(opening); + mDisplayContent.mClosingApps.add(closing); + assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task)); + closing.getTask().removeChild(closing); + task.addChild(closing, 0); + assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task)); + assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_TASK_OPEN, task)); + } + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 98333b244e3b..e60e54c9e44f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -25,6 +25,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -58,12 +60,15 @@ import android.annotation.SuppressLint; import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Rect; +import android.graphics.Region; import android.metrics.LogMaker; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; +import android.util.MutableBoolean; import android.view.DisplayCutout; import android.view.Gravity; +import android.view.ISystemGestureExclusionListener; import android.view.MotionEvent; import android.view.Surface; import android.view.ViewRootImpl; @@ -683,6 +688,60 @@ public class DisplayContentTests extends WindowTestsBase { } @Test + public void testUpdateSystemGestureExclusion() throws Exception { + final DisplayContent dc = createNewDisplay(); + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40))); + + dc.setLayoutNeeded(); + dc.performLayout(true /* initial */, false /* updateImeWindows */); + + win.setHasSurface(true); + dc.updateSystemGestureExclusion(); + + final MutableBoolean invoked = new MutableBoolean(false); + final ISystemGestureExclusionListener.Stub verifier = + new ISystemGestureExclusionListener.Stub() { + @Override + public void onSystemGestureExclusionChanged(int displayId, Region actual) { + Region expected = Region.obtain(); + expected.set(10, 20, 30, 40); + assertEquals(expected, actual); + invoked.value = true; + } + }; + try { + dc.registerSystemGestureExclusionListener(verifier); + } finally { + dc.unregisterSystemGestureExclusionListener(verifier); + } + assertTrue("SystemGestureExclusionListener was not invoked", invoked.value); + } + + @Test + public void testCalculateSystemGestureExclusion() throws Exception { + final DisplayContent dc = createNewDisplay(); + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40))); + + final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2"); + win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50))); + + dc.setLayoutNeeded(); + dc.performLayout(true /* initial */, false /* updateImeWindows */); + + win.setHasSurface(true); + win2.setHasSurface(true); + + final Region expected = Region.obtain(); + expected.set(20, 30, 40, 50); + assertEquals(expected, dc.calculateSystemGestureExclusion()); + } + + @Test public void testOrientationChangeLogging() { MetricsLogger mockLogger = mock(MetricsLogger.class); Configuration oldConfig = new Configuration(); diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index 02eddf67e25b..8c686f704967 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -31,7 +31,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public class ImsException extends Exception { +public final class ImsException extends Exception { /** * The operation has failed due to an unknown or unspecified error. diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java index 8a925b9bad38..ebe54187ddb6 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java @@ -63,6 +63,13 @@ class RollbackBroadcastReceiver extends BroadcastReceiver { } /** + * Waits forever for the next rollback broadcast. + */ + Intent take() throws InterruptedException { + return mRollbackBroadcasts.take(); + } + + /** * Unregisters this broadcast receiver. */ void unregister() { diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 377abc320b2c..52919df1cf0a 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -27,7 +27,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import android.Manifest; -import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -46,8 +45,6 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.Collections; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** @@ -87,7 +84,8 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.TEST_MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS, + Manifest.permission.MANAGE_ROLLBACKS); // Register a broadcast receiver for notification when the // rollback has been committed. @@ -859,34 +857,14 @@ public class RollbackTest { rm.getAvailableRollbacks(), TEST_APP_B); assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB); - BlockingQueue<Integer> crashQueue = new SynchronousQueue<>(); - - IntentFilter crashCountFilter = new IntentFilter(); - crashCountFilter.addAction("com.android.tests.rollback.CRASH"); - crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT); - - crashCountReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - try { - // Sleep long enough for packagewatchdog to be notified of crash - Thread.sleep(1000); - // Kill app and close AppErrorDialog - ActivityManager am = context.getSystemService(ActivityManager.class); - am.killBackgroundProcesses(TEST_APP_A); - // Allow another package launch - crashQueue.put(intent.getIntExtra("count", 0)); - } catch (InterruptedException e) { - fail("Failed to communicate with test app"); - } - } - }; - context.registerReceiver(crashCountReceiver, crashCountFilter); - - // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes - do { - RollbackTestUtils.launchPackage(TEST_APP_A); - } while(crashQueue.take() < 5); + // Register rollback committed receiver + RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver(); + + // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback + crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5); + + // Verify we received a broadcast for the rollback. + rollbackReceiver.take(); // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java index 9aed0748266a..81629aaaec76 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import android.app.ActivityManager; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -47,6 +48,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; /** * Utilities to facilitate testing rollbacks. @@ -187,7 +189,7 @@ class RollbackTestUtils { } /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */ - static void launchPackage(String packageName) + private static void launchPackage(String packageName) throws InterruptedException, IOException { Context context = InstrumentationRegistry.getContext(); Intent intent = new Intent(Intent.ACTION_MAIN); @@ -488,4 +490,39 @@ class RollbackTestUtils { } return null; } + + /** + * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least + * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered. + */ + static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count) + throws InterruptedException, IOException { + BlockingQueue<Integer> crashQueue = new SynchronousQueue<>(); + IntentFilter crashCountFilter = new IntentFilter(); + crashCountFilter.addAction("com.android.tests.rollback.CRASH"); + crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT); + + BroadcastReceiver crashCountReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + try { + // Sleep long enough for packagewatchdog to be notified of crash + Thread.sleep(1000); + // Kill app and close AppErrorDialog + ActivityManager am = context.getSystemService(ActivityManager.class); + am.killBackgroundProcesses(packageName); + // Allow another package launch + crashQueue.put(intent.getIntExtra("count", 0)); + } catch (InterruptedException e) { + fail("Failed to communicate with test app"); + } + } + }; + context.registerReceiver(crashCountReceiver, crashCountFilter); + + do { + launchPackage(packageName); + } while(crashQueue.take() < count); + return crashCountReceiver; + } } diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index e9375176f26b..a24e0d2f93d0 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -58,7 +58,7 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overla // valid. This is because un-mangled references are mangled, then looked up at resolution // time. Also, when linking, we convert references with no package name to use the compilation // package name. - error |= !DoMerge(src, table, package.get(), false /*mangle*/, overlay, allow_new); + error |= !DoMerge(src, package.get(), false /*mangle*/, overlay, allow_new); } } return !error; @@ -78,7 +78,7 @@ bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_n bool mangle = package_name != context_->GetCompilationPackage(); merged_packages_.insert(package->name); - error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/); + error |= !DoMerge(src, package.get(), mangle, false /*overlay*/, true /*allow_new*/); } return !error; } @@ -213,9 +213,8 @@ static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context, return collision_result; } -bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table, - ResourceTablePackage* src_package, bool mangle_package, bool overlay, - bool allow_new_resources) { +bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package, + bool overlay, bool allow_new_resources) { bool error = false; for (auto& src_type : src_package->types) { @@ -337,8 +336,7 @@ bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFi ->FindOrCreateValue(file_desc.config, {}) ->value = std::move(file_ref); - return DoMerge(file->GetSource(), &table, pkg, false /*mangle*/, overlay /*overlay*/, - true /*allow_new*/); + return DoMerge(file->GetSource(), pkg, false /*mangle*/, overlay /*overlay*/, true /*allow_new*/); } } // namespace aapt diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h index 24c5e1329244..51305cfcdd25 100644 --- a/tools/aapt2/link/TableMerger.h +++ b/tools/aapt2/link/TableMerger.h @@ -85,8 +85,8 @@ class TableMerger { bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new); - bool DoMerge(const Source& src, ResourceTable* src_table, ResourceTablePackage* src_package, - bool mangle_package, bool overlay, bool allow_new_resources); + bool DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package, + bool overlay, bool allow_new_resources); std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package, const FileReference& value); |