diff options
49 files changed, 741 insertions, 154 deletions
diff --git a/apex/media/framework/java/android/media/Session2CommandGroup.java b/apex/media/framework/java/android/media/Session2CommandGroup.java index 13aabfc45ab7..af8184a27f0d 100644 --- a/apex/media/framework/java/android/media/Session2CommandGroup.java +++ b/apex/media/framework/java/android/media/Session2CommandGroup.java @@ -68,7 +68,7 @@ public final class Session2CommandGroup implements Parcelable { /** * Used by parcelable creator. */ - @SuppressWarnings("WeakerAccess") /* synthetic access */ + @SuppressWarnings({"WeakerAccess", "UnsafeParcelApi"}) /* synthetic access */ Session2CommandGroup(Parcel in) { Parcelable[] commands = in.readParcelableArray(Session2Command.class.getClassLoader()); if (commands != null) { diff --git a/api/Android.bp b/api/Android.bp index 2e49a0c56778..70f995a44c86 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -24,6 +24,19 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +bootstrap_go_package { + name: "soong-api", + pkgPath: "android/soong/api", + deps: [ + "blueprint", + "soong", + "soong-android", + "soong-genrule", + ], + srcs: ["api.go"], + pluginFor: ["soong_build"], +} + python_defaults { name: "python3_version_defaults", version: { diff --git a/api/api.go b/api/api.go new file mode 100644 index 000000000000..976b140f407f --- /dev/null +++ b/api/api.go @@ -0,0 +1,224 @@ +// Copyright (C) 2021 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 api + +import ( + "github.com/google/blueprint/proptools" + + "android/soong/android" + "android/soong/genrule" +) + +// The intention behind this soong plugin is to generate a number of "merged" +// API-related modules that would otherwise require a large amount of very +// similar Android.bp boilerplate to define. For example, the merged current.txt +// API definitions (created by merging the non-updatable current.txt with all +// the module current.txts). This simplifies the addition of new android +// modules, by reducing the number of genrules etc a new module must be added to. + +// The properties of the combined_apis module type. +type CombinedApisProperties struct { + // Module libraries that have public APIs + Public []string + // Module libraries that have system APIs + System []string + // Module libraries that have module_library APIs + Module_lib []string + // Module libraries that have system_server APIs + System_server []string + // ART module library. The only API library not removed from the filtered api database, because + // 1) ART apis are available by default to all modules, while other module-to-module deps are + // explicit and probably receive more scrutiny anyway + // 2) The number of ART/libcore APIs is large, so not linting them would create a large gap + // 3) It's a compromise. Ideally we wouldn't be filtering out any module APIs, and have + // per-module lint databases that excludes just that module's APIs. Alas, that's more + // difficult to achieve. + Art_module string +} + +type CombinedApis struct { + android.ModuleBase + + properties CombinedApisProperties +} + +func init() { + registerBuildComponents(android.InitRegistrationContext) +} + +func registerBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory) +} + +var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents) + +func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) { +} + +type genruleProps struct { + Name *string + Cmd *string + Dists []android.Dist + Out []string + Srcs []string + Tools []string + Visibility []string +} + +// Struct to pass parameters for the various merged [current|removed].txt file modules we create. +type MergedTxtDefinition struct { + // "current.txt" or "removed.txt" + TxtFilename string + // The module for the non-updatable / non-module part of the api. + BaseTxt string + // The list of modules that are relevant for this merged txt. + Modules []string + // The output tag for each module to use.e.g. {.public.api.txt} for current.txt + ModuleTag string + // public, system, module-lib or system-server + Scope string +} + +func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) { + metalavaCmd := "$(location metalava)" + // Silence reflection warnings. See b/168689341 + metalavaCmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " + metalavaCmd += " --quiet --no-banner --format=v2 " + + filename := txt.TxtFilename + if txt.Scope != "public" { + filename = txt.Scope + "-" + filename + } + + props := genruleProps{} + props.Name = proptools.StringPtr(ctx.ModuleName() + "-" + filename) + props.Tools = []string{"metalava"} + props.Out = []string{txt.TxtFilename} + props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --api $(out)") + props.Srcs = createSrcs(txt.BaseTxt, txt.Modules, txt.ModuleTag) + props.Dists = []android.Dist{ + { + Targets: []string{"droidcore"}, + Dir: proptools.StringPtr("api"), + Dest: proptools.StringPtr(filename), + }, + { + Targets: []string{"sdk"}, + Dir: proptools.StringPtr("apistubs/android/" + txt.Scope + "/api"), + Dest: proptools.StringPtr(txt.TxtFilename), + }, + } + props.Visibility = []string{"//visibility:public"} + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +func createMergedStubsSrcjar(ctx android.LoadHookContext, modules []string) { + props := genruleProps{} + props.Name = proptools.StringPtr(ctx.ModuleName() + "-current.srcjar") + props.Tools = []string{"merge_zips"} + props.Out = []string{"current.srcjar"} + props.Cmd = proptools.StringPtr("$(location merge_zips) $(out) $(in)") + props.Srcs = createSrcs(":api-stubs-docs-non-updatable", modules, "{.public.stubs.source}") + props.Visibility = []string{"//visibility:private"} // Used by make module in //development, mind + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) { + props := genruleProps{} + props.Name = proptools.StringPtr("api-versions-xml-public-filtered") + props.Tools = []string{"api_versions_trimmer"} + props.Out = []string{"api-versions-public-filtered.xml"} + props.Cmd = proptools.StringPtr("$(location api_versions_trimmer) $(out) $(in)") + // Note: order matters: first parameter is the full api-versions.xml + // after that the stubs files in any order + // stubs files are all modules that export API surfaces EXCEPT ART + props.Srcs = createSrcs(":framework-doc-stubs{.api_versions.xml}", modules, ".stubs{.jar}") + props.Dists = []android.Dist{{Targets: []string{"sdk"}}} + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +func createSrcs(base string, modules []string, tag string) []string { + a := make([]string, 0, len(modules)+1) + a = append(a, base) + for _, module := range modules { + a = append(a, ":"+module+tag) + } + return a +} + +func remove(s []string, v string) []string { + s2 := make([]string, 0, len(s)) + for _, sv := range s { + if sv != v { + s2 = append(s2, sv) + } + } + return s2 +} + +func createMergedTxts(ctx android.LoadHookContext, props CombinedApisProperties) { + var textFiles []MergedTxtDefinition + tagSuffix := []string{".api.txt}", ".removed-api.txt}"} + for i, f := range []string{"current.txt", "removed.txt"} { + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-" + f, + Modules: props.Public, + ModuleTag: "{.public" + tagSuffix[i], + Scope: "public", + }) + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-system-" + f, + Modules: props.System, + ModuleTag: "{.system" + tagSuffix[i], + Scope: "system", + }) + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-module-lib-" + f, + Modules: props.Module_lib, + ModuleTag: "{.module-lib" + tagSuffix[i], + Scope: "module-lib", + }) + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-system-server-" + f, + Modules: props.System_server, + ModuleTag: "{.system-server" + tagSuffix[i], + Scope: "system-server", + }) + } + for _, txt := range textFiles { + createMergedTxt(ctx, txt) + } +} + +func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { + createMergedTxts(ctx, a.properties) + + createMergedStubsSrcjar(ctx, a.properties.Public) + + // For the filtered api versions, we prune all APIs except art module's APIs. + createFilteredApiVersions(ctx, remove(a.properties.Public, a.properties.Art_module)) +} + +func combinedApisModuleFactory() android.Module { + module := &CombinedApis{} + module.AddProperties(&module.properties) + android.InitAndroidModule(module) + android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) }) + return module +} diff --git a/core/api/current.txt b/core/api/current.txt index 7f0ff7f9955e..407855b107cd 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -40266,6 +40266,7 @@ package android.telecom { field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800 field public static final int PROPERTY_RTT = 1024; // 0x400 field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100 + field public static final int PROPERTY_TETHERED_CALL = 32768; // 0x8000 field public static final int PROPERTY_VOIP_AUDIO_MODE = 4096; // 0x1000 field public static final int PROPERTY_WIFI = 8; // 0x8 } @@ -40294,6 +40295,7 @@ package android.telecom { field @NonNull public static final android.os.Parcelable.Creator<android.telecom.CallAudioState> CREATOR; field public static final int ROUTE_BLUETOOTH = 2; // 0x2 field public static final int ROUTE_EARPIECE = 1; // 0x1 + field public static final int ROUTE_EXTERNAL = 16; // 0x10 field public static final int ROUTE_SPEAKER = 8; // 0x8 field public static final int ROUTE_WIRED_HEADSET = 4; // 0x4 field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5 @@ -40568,6 +40570,7 @@ package android.telecom { field public static final int PROPERTY_IS_RTT = 256; // 0x100 field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400 field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80 + field public static final int PROPERTY_TETHERED_CALL = 16384; // 0x4000 field public static final int PROPERTY_WIFI = 8; // 0x8 field public static final int STATE_ACTIVE = 4; // 0x4 field public static final int STATE_DIALING = 3; // 0x3 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 67567a657e2e..3a3813f29d89 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -165,6 +165,7 @@ package android { field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS"; field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS"; field public static final String MANAGE_ROTATION_RESOLVER = "android.permission.MANAGE_ROTATION_RESOLVER"; + field public static final String MANAGE_SAFETY_CENTER = "android.permission.MANAGE_SAFETY_CENTER"; field public static final String MANAGE_SEARCH_UI = "android.permission.MANAGE_SEARCH_UI"; field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY"; field public static final String MANAGE_SMARTSPACE = "android.permission.MANAGE_SMARTSPACE"; @@ -403,6 +404,7 @@ package android { field public static final int config_systemAmbientAudioIntelligence = 17039411; // 0x1040033 field public static final int config_systemAppProtectionService; field public static final int config_systemAudioIntelligence = 17039412; // 0x1040034 + field public static final int config_systemAutomotiveCalendarSyncManager; field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029 field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 34ee0aa55e51..66250fcebe92 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -36,6 +36,7 @@ package android { field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS"; + field public static final String REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL = "android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL"; field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS"; field public static final String START_TASKS_FROM_RECENTS = "android.permission.START_TASKS_FROM_RECENTS"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; @@ -66,6 +67,7 @@ package android { public static final class R.string { field public static final int config_defaultAssistant = 17039393; // 0x1040021 field public static final int config_defaultDialer = 17039395; // 0x1040023 + field public static final int config_systemAutomotiveCalendarSyncManager; field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029 field public static final int config_systemGallery = 17039399; // 0x1040027 @@ -2044,6 +2046,7 @@ package android.permission { method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(); method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(boolean); method @NonNull public android.content.AttributionSource registerAttributionSource(@NonNull android.content.AttributionSource); + method public void revokePostNotificationPermissionWithoutKillForTest(@NonNull String, int); } } @@ -2317,6 +2320,7 @@ package android.service.dreams { method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onStartDream(@NonNull android.view.WindowManager.LayoutParams); method public final void requestExit(); + method public final boolean shouldShowComplications(); } } diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java index a821dadf4948..857c5416b3bc 100644 --- a/core/java/android/accessibilityservice/GestureDescription.java +++ b/core/java/android/accessibilityservice/GestureDescription.java @@ -525,7 +525,7 @@ public final class GestureDescription { public GestureStep(Parcel parcel) { timeSinceGestureStart = parcel.readLong(); Parcelable[] parcelables = - parcel.readParcelableArray(TouchPoint.class.getClassLoader()); + parcel.readParcelableArray(TouchPoint.class.getClassLoader(), TouchPoint.class); numTouchPoints = (parcelables == null) ? 0 : parcelables.length; touchPoints = new TouchPoint[numTouchPoints]; for (int i = 0; i < numTouchPoints; i++) { diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java index 63fcb49fff1b..8fd41f2c9e05 100644 --- a/core/java/android/content/RestrictionEntry.java +++ b/core/java/android/content/RestrictionEntry.java @@ -505,7 +505,7 @@ public class RestrictionEntry implements Parcelable { mChoiceValues = in.readStringArray(); mCurrentValue = in.readString(); mCurrentValues = in.readStringArray(); - Parcelable[] parcelables = in.readParcelableArray(null); + Parcelable[] parcelables = in.readParcelableArray(null, RestrictionEntry.class); if (parcelables != null) { mRestrictions = new RestrictionEntry[parcelables.length]; for (int i = 0; i < parcelables.length; i++) { diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java index 7714dd80f910..243f80187185 100644 --- a/core/java/android/debug/AdbManager.java +++ b/core/java/android/debug/AdbManager.java @@ -38,6 +38,7 @@ public class AdbManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public static final String WIRELESS_DEBUG_STATE_CHANGED_ACTION = "com.android.server.adb.WIRELESS_DEBUG_STATUS"; @@ -46,6 +47,7 @@ public class AdbManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public static final String WIRELESS_DEBUG_PAIRED_DEVICES_ACTION = "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES"; @@ -59,6 +61,7 @@ public class AdbManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public static final String WIRELESS_DEBUG_PAIRING_RESULT_ACTION = "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT"; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 86ae3a311c9b..5df64e3cca9e 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -599,7 +599,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> synchronized (mSurfacesLock) { mSurfaceSet.clear(); - Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader()); + Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader(), + Surface.class); if (parcelableArray != null) { for (Parcelable p : parcelableArray) { Surface s = (Surface) p; diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 6ea2ac414704..4cc001a40146 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -436,7 +436,8 @@ public class RadioManager { mNumAudioSources = in.readInt(); mIsInitializationRequired = in.readInt() == 1; mIsCaptureSupported = in.readInt() == 1; - Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader()); + Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader(), + BandDescriptor.class); mBands = new BandDescriptor[tmp.length]; for (int i = 0; i < tmp.length; i++) { mBands[i] = (BandDescriptor) tmp[i]; diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl index 4a94c32501a1..90b5e518ef1b 100644 --- a/core/java/android/permission/IPermissionManager.aidl +++ b/core/java/android/permission/IPermissionManager.aidl @@ -67,6 +67,8 @@ interface IPermissionManager { void revokeRuntimePermission(String packageName, String permissionName, int userId, String reason); + void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId); + boolean shouldShowRequestPermissionRationale(String packageName, String permissionName, int userId); diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 3ea50e98879b..4f2287606e05 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -1362,6 +1362,26 @@ public final class PermissionManager { return false; } + /** + * Revoke the POST_NOTIFICATIONS permission, without killing the app. This method must ONLY BE + * USED in CTS or local tests. + * + * @param packageName The package to be revoked + * @param userId The user for which to revoke + * + * @hide + */ + @TestApi + public void revokePostNotificationPermissionWithoutKillForTest(@NonNull String packageName, + int userId) { + try { + mPermissionManager.revokePostNotificationPermissionWithoutKillForTest(packageName, + userId); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + /* @hide */ private static int checkPermissionUncached(@Nullable String permission, int pid, int uid) { final IActivityManager am = ActivityManager.getService(); diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java index 9bdfd8e69c00..9d0c8d82ed0d 100644 --- a/core/java/android/print/PrintJobInfo.java +++ b/core/java/android/print/PrintJobInfo.java @@ -240,7 +240,7 @@ public final class PrintJobInfo implements Parcelable { mTag = parcel.readString(); mCreationTime = parcel.readLong(); mCopies = parcel.readInt(); - Parcelable[] parcelables = parcel.readParcelableArray(null); + Parcelable[] parcelables = parcel.readParcelableArray(null, PageRange.class); if (parcelables != null) { mPageRanges = new PageRange[parcelables.length]; for (int i = 0; i < parcelables.length; i++) { diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java index 50f9d8ac2958..163d6ed4b18b 100644 --- a/core/java/android/service/dreams/DreamOverlayService.java +++ b/core/java/android/service/dreams/DreamOverlayService.java @@ -35,6 +35,7 @@ import android.view.WindowManager; public abstract class DreamOverlayService extends Service { private static final String TAG = "DreamOverlayService"; private static final boolean DEBUG = false; + private boolean mShowComplications; private IDreamOverlay mDreamOverlay = new IDreamOverlay.Stub() { @Override @@ -53,6 +54,8 @@ public abstract class DreamOverlayService extends Service { @Nullable @Override public final IBinder onBind(@NonNull Intent intent) { + mShowComplications = intent.getBooleanExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, + DreamService.DEFAULT_SHOW_COMPLICATIONS); return mDreamOverlay.asBinder(); } @@ -74,4 +77,11 @@ public abstract class DreamOverlayService extends Service { Log.e(TAG, "Could not request exit:" + e); } } + + /** + * Returns whether to show complications on the dream overlay. + */ + public final boolean shouldShowComplications() { + return mShowComplications; + } } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 4ae3d7de26c2..133e384dfa8f 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -189,6 +189,19 @@ public class DreamService extends Service implements Window.Callback { */ public static final String DREAM_META_DATA = "android.service.dream"; + /** + * Extra containing a boolean for whether to show complications on the overlay. + * @hide + */ + public static final String EXTRA_SHOW_COMPLICATIONS = + "android.service.dreams.SHOW_COMPLICATIONS"; + + /** + * The default value for whether to show complications on the overlay. + * @hide + */ + public static final boolean DEFAULT_SHOW_COMPLICATIONS = true; + private final IDreamManager mDreamManager; private final Handler mHandler = new Handler(Looper.getMainLooper()); private IBinder mDreamToken; diff --git a/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java b/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java index 733c0afff367..0130ef47010a 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java @@ -190,7 +190,7 @@ public class PresResInstanceInfo implements Parcelable{ mResInstanceState = source.readInt(); mPresentityUri = source.readString(); Parcelable[] tempParcelableArray = source.readParcelableArray( - PresTupleInfo.class.getClassLoader()); + PresTupleInfo.class.getClassLoader(), PresTupleInfo.class); mTupleInfoArray = new PresTupleInfo[] {}; if(tempParcelableArray != null) { mTupleInfoArray = Arrays.copyOf(tempParcelableArray, tempParcelableArray.length, diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java index 289daee26f52..301de2d3529e 100644 --- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java +++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java @@ -239,7 +239,8 @@ public class DisplayResolveInfo implements TargetInfo, Parcelable { mExtendedInfo = in.readCharSequence(); mResolvedIntent = in.readParcelable(null /* ClassLoader */, android.content.Intent.class); mSourceIntents.addAll( - Arrays.asList((Intent[]) in.readParcelableArray(null /* ClassLoader */))); + Arrays.asList((Intent[]) in.readParcelableArray(null /* ClassLoader */, + Intent.class))); mIsSuspended = in.readBoolean(); mPinned = in.readBoolean(); mResolveInfo = in.readParcelable(null /* ClassLoader */, android.content.pm.ResolveInfo.class); diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java index 84391c169941..0443ad03b6ea 100644 --- a/core/java/com/android/internal/infra/AndroidFuture.java +++ b/core/java/com/android/internal/infra/AndroidFuture.java @@ -24,7 +24,6 @@ import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; -import android.util.EventLog; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -585,6 +584,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable /** * @see #writeThrowable */ + @SuppressWarnings("UnsafeParcelApi") private static @Nullable Throwable readThrowable(@NonNull Parcel parcel) { final boolean hasThrowable = parcel.readBoolean(); if (!hasThrowable) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index dfcfd5f295e2..ae5414d4fa47 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4438,6 +4438,12 @@ <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" android:protectionLevel="signature|installer|verifier" /> + <!-- @TestApi Allows an application to revoke the POST_NOTIFICATIONS permission from an app + without killing the app. Only granted to the shell. + @hide --> + <permission android:name="android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows the system to read runtime permission state. @hide --> <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" @@ -6094,7 +6100,7 @@ @hide --> <permission android:name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES" android:protectionLevel="signature|role" /> - + <!-- @SystemApi Allows an app to read whether SafetyCenter is enabled/disabled. <p>Protection level: signature|privileged @hide @@ -6102,6 +6108,14 @@ <permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Required to access the safety center internal APIs using the + {@link android.safetycenter.SafetyCenterManager}. + <p>Protection level: internal|installer|role + @hide + --> + <permission android:name="android.permission.MANAGE_SAFETY_CENTER" + android:protectionLevel="internal|installer|role" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 5470e33df12a..2836c9816886 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2133,6 +2133,8 @@ <string name="config_deviceManager" translatable="false"></string> <!-- The name of the package that will hold the app protection service role. --> <string name="config_systemAppProtectionService" translatable="false"></string> + <!-- The name of the package that will hold the system calendar sync manager role. --> + <string name="config_systemAutomotiveCalendarSyncManager" translatable="false"></string> <!-- The name of the package that will be allowed to change its components' label/icon. --> <string name="config_overrideComponentUiPackage" translatable="false">com.android.stk</string> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 3bd8ec3943bc..5fa7409150ab 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3274,6 +3274,8 @@ <public name="config_deviceManager" /> <!-- @hide @SystemApi --> <public name="config_systemAppProtectionService" /> + <!-- @hide @SystemApi @TestApi --> + <public name="config_systemAutomotiveCalendarSyncManager" /> </staging-public-group> <staging-public-group type="dimen" first-id="0x01db0000"> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 3b4b9e5dd33b..878d302d481e 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -519,9 +519,8 @@ applications that come with the platform <permission name="android.permission.MANAGE_VOICE_KEYPHRASES" /> <!-- Permission required for ATS test - CarDevicePolicyManagerTest --> <permission name="android.permission.LOCK_DEVICE" /> - <!-- Permission required for CTS test - CtsSafetyCenterTestCases --> + <!-- Permissions required for CTS test - CtsSafetyCenterTestCases --> <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" /> - <!-- Permission required for CTS test - CtsSafetyCenterTestCases --> <permission name="android.permission.READ_SAFETY_CENTER_STATUS" /> </privapp-permissions> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java index 9374da4c4fab..f878a46d26f2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java @@ -231,8 +231,9 @@ public class BubbleFlyoutView extends FrameLayout { * Fade animation for consecutive flyouts. */ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, PointF stackPos, - boolean hideDot, Runnable onHide) { + boolean hideDot, float[] dotCenter, Runnable onHide) { mOnHide = onHide; + mDotCenter = dotCenter; final Runnable afterFadeOut = () -> { updateFlyoutMessage(flyoutMessage); // Wait for TextViews to layout with updated height. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 7bf4439410f9..d5d8b71056d6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -2516,6 +2516,7 @@ public class BubbleStackView extends FrameLayout if (mFlyout.getVisibility() == View.VISIBLE) { mFlyout.animateUpdate(bubble.getFlyoutMessage(), mStackAnimationController.getStackPosition(), !bubble.showDot(), + bubble.getIconView().getDotCenter(), mAfterFlyoutHidden /* onHide */); } else { mFlyout.setVisibility(INVISIBLE); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index dd07f91ef38b..0c70821527dd 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -608,11 +608,14 @@ <!-- Permission required for ATS test - CarDevicePolicyManagerTest --> <uses-permission android:name="android.permission.LOCK_DEVICE" /> - <!-- Permission required for CTS test - CtsSafetyCenterTestCases --> + <!-- Permissions required for CTS test - CtsSafetyCenterTestCases --> <uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" /> - - <!-- Permission required for CTS test - CtsSafetyCenterTestCases --> <uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" /> + <uses-permission android:name="android.permission.MANAGE_SAFETY_CENTER" /> + + + <!-- Permission required for CTS test - Notification test suite --> + <uses-permission android:name="android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL" /> <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" diff --git a/packages/Shell/res/values-watch/strings.xml b/packages/Shell/res/values-watch/strings.xml new file mode 100644 index 000000000000..5f7bfcb25d85 --- /dev/null +++ b/packages/Shell/res/values-watch/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Title for Bug report notification indicating the number of the bug report and the + percentage complete. Example: "Bug report #3 is 20% complete" [CHAR LIMIT=50] --> + <string name="bugreport_in_progress_title">Bug report <xliff:g id="id" example="#3">#%1$d</xliff:g> is <xliff:g id="percentage" example="20%">%2$s</xliff:g> complete</string> +</resources> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index ee9d4301770a..c5a01a1c2b93 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -199,6 +199,15 @@ public class BugreportProgressService extends Service { */ private static final String BUGREPORT_DIR = "bugreports"; + /** + * The directory in which System Trace files from the native System Tracing app are stored for + * Wear devices. + */ + private static final String WEAR_SYSTEM_TRACES_DIRECTORY_ON_DEVICE = "data/local/traces/"; + + /** The directory that contains System Traces in bugreports that include System Traces. */ + private static final String WEAR_SYSTEM_TRACES_DIRECTORY_IN_BUGREPORT = "systraces/"; + private static final String NOTIFICATION_CHANNEL_ID = "bugreports"; /** @@ -724,14 +733,16 @@ public class BugreportProgressService extends Service { nf.setMaximumFractionDigits(2); final String percentageText = nf.format((double) info.progress.intValue() / 100); - String title = mContext.getString(R.string.bugreport_in_progress_title, info.id); - - // TODO: Remove this workaround when notification progress is implemented on Wear. + final String title; if (mIsWatch) { + // TODO: Remove this workaround when notification progress is implemented on Wear. nf.setMinimumFractionDigits(0); nf.setMaximumFractionDigits(0); final String watchPercentageText = nf.format((double) info.progress.intValue() / 100); - title = title + "\n" + watchPercentageText; + title = mContext.getString( + R.string.bugreport_in_progress_title, info.id, watchPercentageText); + } else { + title = mContext.getString(R.string.bugreport_in_progress_title, info.id); } final String name = @@ -1456,6 +1467,16 @@ public class BugreportProgressService extends Service { } } + /** Returns an array of the system trace files collected by the System Tracing native app. */ + private static File[] getSystemTraceFiles() { + try { + return new File(WEAR_SYSTEM_TRACES_DIRECTORY_ON_DEVICE).listFiles(); + } catch (SecurityException e) { + Log.e(TAG, "Error getting system trace files.", e); + return new File[]{}; + } + } + /** * Adds the user-provided info into the bugreport zip file. * <p> @@ -1475,8 +1496,17 @@ public class BugreportProgressService extends Service { Log.wtf(TAG, "addDetailsToZipFile(): no bugreportFile on " + info); return; } - if (TextUtils.isEmpty(info.getTitle()) && TextUtils.isEmpty(info.getDescription())) { - Log.d(TAG, "Not touching zip file since neither title nor description are set"); + + File[] systemTracesToIncludeInBugreport = new File[] {}; + if (mIsWatch) { + systemTracesToIncludeInBugreport = getSystemTraceFiles(); + Log.d(TAG, "Found " + systemTracesToIncludeInBugreport.length + " system traces."); + } + + if (TextUtils.isEmpty(info.getTitle()) + && TextUtils.isEmpty(info.getDescription()) + && systemTracesToIncludeInBugreport.length == 0) { + Log.d(TAG, "Not touching zip file: no detail to add."); return; } if (info.addedDetailsToZip || info.addingDetailsToZip) { @@ -1487,7 +1517,10 @@ public class BugreportProgressService extends Service { // It's not possible to add a new entry into an existing file, so we need to create a new // zip, copy all entries, then rename it. - sendBugreportBeingUpdatedNotification(mContext, info.id); // ...and that takes time + if (!mIsWatch) { + // TODO(b/184854609): re-introduce this notification for Wear. + sendBugreportBeingUpdatedNotification(mContext, info.id); // ...and that takes time + } final File dir = info.bugreportFile.getParentFile(); final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName()); @@ -1508,6 +1541,13 @@ public class BugreportProgressService extends Service { } // Then add the user-provided info. + if (systemTracesToIncludeInBugreport.length != 0) { + for (File trace : systemTracesToIncludeInBugreport) { + addEntry(zos, + WEAR_SYSTEM_TRACES_DIRECTORY_IN_BUGREPORT + trace.getName(), + new FileInputStream(trace)); + } + } addEntry(zos, "title.txt", info.getTitle()); addEntry(zos, "description.txt", info.getDescription()); } catch (IOException e) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 4658a745b680..094b1927480d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -100,6 +100,7 @@ import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.CoreStartable; +import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.animation.Interpolators; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -2345,16 +2346,20 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // Block the panel from expanding, in case we were doing a swipe to dismiss gesture. mKeyguardViewControllerLazy.get().blockPanelExpansionFromCurrentTouch(); final boolean wasShowing = mShowing; - onKeyguardExitFinished(); + InteractionJankMonitor.getInstance().end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION); - if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) { - mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation(); - } + // Post layout changes to the next frame, so we don't hang at the end of the animation. + DejankUtils.postAfterTraversal(() -> { + onKeyguardExitFinished(); - finishSurfaceBehindRemoteAnimation(cancelled); - mSurfaceBehindRemoteAnimationRequested = false; - mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(); - InteractionJankMonitor.getInstance().end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION); + if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) { + mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation(); + } + + finishSurfaceBehindRemoteAnimation(cancelled); + mSurfaceBehindRemoteAnimationRequested = false; + mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(); + }); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index 8cd8e4d7382d..c0b7271c6de7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -16,12 +16,15 @@ package com.android.systemui.dreams; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Intent; import android.os.IBinder; +import android.service.dreams.DreamService; import android.service.dreams.IDreamOverlay; import android.service.dreams.IDreamOverlayCallback; import android.testing.AndroidTestingRunner; @@ -195,4 +198,22 @@ public class DreamOverlayServiceTest extends SysuiTestCase { mService.onDestroy(); verify(mDreamOverlayStateController).removeCallback(callbackCapture.getValue()); } + + @Test + public void testShouldShowComplicationsTrueByDefault() { + assertThat(mService.shouldShowComplications()).isTrue(); + + mService.onBind(new Intent()); + + assertThat(mService.shouldShowComplications()).isTrue(); + } + + @Test + public void testShouldShowComplicationsSetByIntentExtra() { + final Intent intent = new Intent(); + intent.putExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, false); + mService.onBind(intent); + + assertThat(mService.shouldShowComplications()).isFalse(); + } } diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 5f295ac8f20d..e7f4de2a0588 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -26,6 +26,7 @@ import android.os.Environment; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; +import android.util.ArraySet; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -47,6 +48,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -94,6 +96,7 @@ public final class SystemServiceManager implements Dumpable { // Services that should receive lifecycle events. private List<SystemService> mServices; + private Set<String> mServiceClassnames; private int mCurrentPhase = -1; @@ -116,6 +119,7 @@ public final class SystemServiceManager implements Dumpable { SystemServiceManager(Context context) { mContext = context; mServices = new ArrayList<>(); + mServiceClassnames = new ArraySet<>(); // Disable using the thread pool for low ram devices sUseLifecycleThreadPool = sUseLifecycleThreadPool && !ActivityManager.isLowRamDeviceStatic(); @@ -210,8 +214,17 @@ public final class SystemServiceManager implements Dumpable { } public void startService(@NonNull final SystemService service) { + // Check if already started + String className = service.getClass().getName(); + if (mServiceClassnames.contains(className)) { + Slog.i(TAG, "Not starting an already started service " + className); + return; + } + mServiceClassnames.add(className); + // Register it. mServices.add(service); + // Start it. long time = SystemClock.elapsedRealtime(); try { @@ -225,6 +238,7 @@ public final class SystemServiceManager implements Dumpable { /** Disallow starting new services after this call. */ void sealStartedServices() { + mServiceClassnames = Collections.emptySet(); mServices = Collections.unmodifiableList(mServices); } diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index f591b26f1770..297d28dadde3 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -18,6 +18,7 @@ package com.android.server.adb; import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull; +import android.annotation.NonNull; import android.annotation.TestApi; import android.app.ActivityManager; import android.app.Notification; @@ -170,6 +171,12 @@ public class AdbDebuggingManager { mAdbConnectionInfo = new AdbConnectionInfo(); } + static void sendBroadcastWithDebugPermission(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle userHandle) { + context.sendBroadcastAsUser(intent, userHandle, + android.Manifest.permission.MANAGE_DEBUGGING); + } + class PairingThread extends Thread implements NsdManager.RegistrationListener { private NsdManager mNsdManager; private String mPublicKey; @@ -1278,7 +1285,7 @@ public class AdbDebuggingManager { ? AdbManager.WIRELESS_STATUS_CONNECTED : AdbManager.WIRELESS_STATUS_DISCONNECTED); intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); } private void onAdbdWifiServerConnected(int port) { @@ -1350,7 +1357,8 @@ public class AdbDebuggingManager { if (publicKey == null) { Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, AdbManager.WIRELESS_STATUS_FAIL); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, + UserHandle.ALL); } else { Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, @@ -1366,7 +1374,8 @@ public class AdbDebuggingManager { device.guid = hostname; device.connected = false; intent.putExtra(AdbManager.WIRELESS_PAIR_DEVICE_EXTRA, device); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, + UserHandle.ALL); // Add the key into the keystore mAdbKeyStore.setLastConnectionTime(publicKey, System.currentTimeMillis()); @@ -1380,14 +1389,14 @@ public class AdbDebuggingManager { intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, AdbManager.WIRELESS_STATUS_CONNECTED); intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); } private void sendPairedDevicesToUI(Map<String, PairDevice> devices) { Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION); // Map is not serializable, so need to downcast intent.putExtra(AdbManager.WIRELESS_DEVICES_EXTRA, (HashMap) devices); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); } private void updateUIPairCode(String code) { @@ -1397,7 +1406,7 @@ public class AdbDebuggingManager { intent.putExtra(AdbManager.WIRELESS_PAIRING_CODE_EXTRA, code); intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, AdbManager.WIRELESS_STATUS_PAIRING_CODE); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); } } diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index 7a4d2ce50cd3..2845fbfc6ebf 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -459,7 +459,7 @@ public class AdbService extends IAdbManager.Stub { ? AdbManager.WIRELESS_STATUS_CONNECTED : AdbManager.WIRELESS_STATUS_DISCONNECTED); intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); Slog.i(TAG, "sent port broadcast port=" + port); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 8d56cda239bc..85e54f3766ea 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -551,6 +551,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override + public void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId) { + mPermissionManagerServiceImpl.revokePostNotificationPermissionWithoutKillForTest( + packageName, userId); + } + + @Override public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName, int userId) { return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName, diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java index c1bedb260dbd..21cb2c96fc6a 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java @@ -167,6 +167,10 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt private static final String TAG = "PackageManager"; private static final String LOG_TAG = PermissionManagerServiceImpl.class.getSimpleName(); + private static final String SKIP_KILL_APP_REASON_NOTIFICATION_TEST = "skip permission revoke " + + "app kill for notification test"; + + private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60); // For automotive products, CarService enforces allow-listing of the privileged permissions @@ -320,11 +324,15 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt mPackageManagerInt.writeSettings(true); } @Override - public void onPermissionRevoked(int uid, int userId, String reason) { + public void onPermissionRevoked(int uid, int userId, String reason, boolean overrideKill) { mOnPermissionChangeListeners.onPermissionsChanged(uid); // Critical; after this call the application should never have the permission mPackageManagerInt.writeSettings(false); + if (overrideKill) { + return; + } + final int appId = UserHandle.getAppId(uid); if (reason == null) { mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED)); @@ -1438,9 +1446,29 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt reason, mDefaultPermissionCallback); } + @Override + public void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId) { + final int callingUid = Binder.getCallingUid(); + final boolean overridePolicy = + checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY) + == PackageManager.PERMISSION_GRANTED; + mContext.enforceCallingPermission( + android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL, ""); + revokeRuntimePermissionInternal(packageName, Manifest.permission.POST_NOTIFICATIONS, + overridePolicy, true, callingUid, userId, + SKIP_KILL_APP_REASON_NOTIFICATION_TEST, mDefaultPermissionCallback); + } + private void revokeRuntimePermissionInternal(String packageName, String permName, - boolean overridePolicy, int callingUid, final int userId, String reason, - PermissionCallback callback) { + boolean overridePolicy, int callingUid, final int userId, + String reason, PermissionCallback callback) { + revokeRuntimePermissionInternal(packageName, permName, overridePolicy, false, callingUid, + userId, reason, callback); + } + + private void revokeRuntimePermissionInternal(String packageName, String permName, + boolean overridePolicy, boolean overrideKill, int callingUid, final int userId, + String reason, PermissionCallback callback) { if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is revoking " + packageName + " " @@ -1552,7 +1580,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt if (callback != null) { if (isRuntimePermission) { callback.onPermissionRevoked(UserHandle.getUid(userId, pkg.getUid()), userId, - reason); + reason, overrideKill); } else { mDefaultPermissionCallback.onInstallPermissionRevoked(); } @@ -5197,7 +5225,11 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt public void onPermissionChanged() {} public void onPermissionGranted(int uid, @UserIdInt int userId) {} public void onInstallPermissionGranted() {} - public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason) {} + public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason) { + onPermissionRevoked(uid, userId, reason, false); + } + public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason, + boolean overrideKill) {} public void onInstallPermissionRevoked() {} public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {} public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync, diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java index d2018f26d04a..3771f030aefa 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java @@ -318,6 +318,15 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte String reason); /** + * Revoke the POST_NOTIFICATIONS permission, without killing the app. This method must ONLY BE + * USED in CTS or local tests. + * + * @param packageName The package to be revoked + * @param userId The user for which to revoke + */ + void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId); + + /** * Get whether you should show UI with rationale for requesting a permission. You should do this * only if you do not have the permission and the context in which the permission is requested * does not clearly communicate to the user what would be the benefit from grating this diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index b91d3a8525e5..5a420caa176c 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -983,29 +983,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mWmService.checkDrawnWindowsLocked(); } - final int N = mWmService.mPendingRemove.size(); - if (N > 0) { - if (mWmService.mPendingRemoveTmp.length < N) { - mWmService.mPendingRemoveTmp = new WindowState[N + 10]; - } - mWmService.mPendingRemove.toArray(mWmService.mPendingRemoveTmp); - mWmService.mPendingRemove.clear(); - ArrayList<DisplayContent> displayList = new ArrayList(); - for (i = 0; i < N; i++) { - final WindowState w = mWmService.mPendingRemoveTmp[i]; - w.removeImmediately(); - final DisplayContent displayContent = w.getDisplayContent(); - if (displayContent != null && !displayList.contains(displayContent)) { - displayList.add(displayContent); - } - } - - for (int j = displayList.size() - 1; j >= 0; --j) { - final DisplayContent dc = displayList.get(j); - dc.assignWindowLayers(true /*setLayoutNeeded*/); - } - } - forAllDisplays(dc -> { dc.getInputMonitor().updateInputWindowsLw(true /*force*/); dc.updateSystemGestureExclusion(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7be128b53f8c..b5e6f49146f1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -222,7 +222,6 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.MergedConfiguration; import android.util.Slog; -import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.TypedValue; @@ -588,20 +587,6 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowState> mResizingWindows = new ArrayList<>(); /** - * Windows whose animations have ended and now must be removed. - */ - final ArrayList<WindowState> mPendingRemove = new ArrayList<>(); - - /** - * Used when processing mPendingRemove to avoid working on the original array. - */ - WindowState[] mPendingRemoveTmp = new WindowState[20]; - - // TODO: use WindowProcessController once go/wm-unified is done. - /** Mapping of process pids to configurations */ - final SparseArray<Configuration> mProcessConfigurations = new SparseArray<>(); - - /** * Windows whose surface should be destroyed. */ final ArrayList<WindowState> mDestroySurface = new ArrayList<>(); @@ -2038,7 +2023,6 @@ public class WindowManagerService extends IWindowManager.Stub dc.mWinRemovedSinceNullFocus.add(win); } mEmbeddedWindowController.onWindowRemoved(win); - mPendingRemove.remove(win); mResizingWindows.remove(win); updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */); mWindowsChanged = true; @@ -6342,23 +6326,6 @@ public class WindowManagerService extends IWindowManager.Stub } } } - if (mPendingRemove.size() > 0) { - pw.println(); - pw.println(" Remove pending for:"); - for (int i=mPendingRemove.size()-1; i>=0; i--) { - WindowState w = mPendingRemove.get(i); - if (windows == null || windows.contains(w)) { - pw.print(" Remove #"); pw.print(i); pw.print(' '); - pw.print(w); - if (dumpAll) { - pw.println(":"); - w.dump(pw, " ", true); - } else { - pw.println(); - } - } - } - } if (mForceRemoves != null && mForceRemoves.size() > 0) { pw.println(); pw.println(" Windows force removing:"); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 6acd4548392a..5bbe2cd853f6 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4835,15 +4835,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (hasSurface) { mWmService.mDestroySurface.add(this); } - if (mRemoveOnExit) { - mWmService.mPendingRemove.add(this); - mRemoveOnExit = false; - } } mAnimatingExit = false; getDisplayContent().mWallpaperController.hideWallpapers(this); } + @Override + boolean handleCompleteDeferredRemoval() { + if (mRemoveOnExit) { + mRemoveOnExit = false; + removeImmediately(); + } + return super.handleCompleteDeferredRemoval(); + } + boolean clearAnimatingFlags() { boolean didSomething = false; // We don't want to clear it out for windows that get replaced, because the diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 4673a6905fc0..e0b8672a0ac0 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -3053,7 +3053,6 @@ public final class SystemServer implements Dumpable { private void startApexServices(@NonNull TimingsTraceAndSlog t) { t.traceBegin("startApexServices"); Map<String, String> services = ApexManager.getInstance().getApexSystemServices(); - // TODO(satayev): filter out already started services // TODO(satayev): introduce android:order for services coming the same apexes for (String name : new TreeSet<>(services.keySet())) { String jarPath = services.get(name); diff --git a/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java b/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java index 4413dc8b9734..f92f5ead2c3b 100644 --- a/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java @@ -23,6 +23,7 @@ import android.test.AndroidTestCase; import org.junit.Test; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; /** @@ -32,24 +33,52 @@ public class SystemServiceManagerTest extends AndroidTestCase { private static final String TAG = "SystemServiceManagerTest"; + private final SystemServiceManager mSystemServiceManager = + new SystemServiceManager(getContext()); + @Test public void testSealStartedServices() throws Exception { - SystemServiceManager manager = new SystemServiceManager(getContext()); // must be effectively final, since it's changed from inner class below AtomicBoolean serviceStarted = new AtomicBoolean(false); - SystemService service = new SystemService(getContext()) { + SystemService service1 = new SystemService(getContext()) { @Override public void onStart() { serviceStarted.set(true); } }; + SystemService service2 = new SystemService(getContext()) { + @Override + public void onStart() { + throw new IllegalStateException("Second service must not be called"); + } + }; // started services have their #onStart methods called - manager.startService(service); + mSystemServiceManager.startService(service1); assertTrue(serviceStarted.get()); // however, after locking started services, it is not possible to start a new service - manager.sealStartedServices(); - assertThrows(UnsupportedOperationException.class, () -> manager.startService(service)); + mSystemServiceManager.sealStartedServices(); + assertThrows(UnsupportedOperationException.class, + () -> mSystemServiceManager.startService(service2)); } + + @Test + public void testDuplicateServices() throws Exception { + AtomicInteger counter = new AtomicInteger(0); + SystemService service = new SystemService(getContext()) { + @Override + public void onStart() { + counter.incrementAndGet(); + } + }; + + mSystemServiceManager.startService(service); + assertEquals(1, counter.get()); + + // manager does not start the same service twice + mSystemServiceManager.startService(service); + assertEquals(1, counter.get()); + } + } diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java index cffff66b64f1..02cf971a8076 100644 --- a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java @@ -23,7 +23,14 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.debug.AdbManager; +import android.debug.IAdbManager; +import android.os.ServiceManager; import android.provider.Settings; import android.util.Log; @@ -105,6 +112,7 @@ public final class AdbDebuggingManagerTest { public void tearDown() throws Exception { mKeyStore.deleteKeyStore(); setAllowedConnectionTime(mOriginalAllowedConnectionTime); + dropShellPermissionIdentity(); } /** @@ -813,6 +821,108 @@ public final class AdbDebuggingManagerTest { return hasAtLeastOneLetter; } + CountDownLatch mAdbActionLatch = new CountDownLatch(1); + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.i(TAG, "Received intent action=" + action); + if (AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION.equals(action)) { + assertEquals("Received broadcast without MANAGE_DEBUGGING permission.", + context.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING), + PackageManager.PERMISSION_GRANTED); + Log.i(TAG, "action=" + action + " paired_device=" + intent.getSerializableExtra( + AdbManager.WIRELESS_DEVICES_EXTRA).toString()); + mAdbActionLatch.countDown(); + } else if (AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION.equals(action)) { + assertEquals("Received broadcast without MANAGE_DEBUGGING permission.", + context.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING), + PackageManager.PERMISSION_GRANTED); + int status = intent.getIntExtra(AdbManager.WIRELESS_STATUS_EXTRA, + AdbManager.WIRELESS_STATUS_DISCONNECTED); + Log.i(TAG, "action=" + action + " status=" + status); + mAdbActionLatch.countDown(); + } else if (AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION.equals(action)) { + assertEquals("Received broadcast without MANAGE_DEBUGGING permission.", + context.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING), + PackageManager.PERMISSION_GRANTED); + Integer res = intent.getIntExtra( + AdbManager.WIRELESS_STATUS_EXTRA, + AdbManager.WIRELESS_STATUS_FAIL); + Log.i(TAG, "action=" + action + " result=" + res); + + if (res.equals(AdbManager.WIRELESS_STATUS_PAIRING_CODE)) { + String pairingCode = intent.getStringExtra( + AdbManager.WIRELESS_PAIRING_CODE_EXTRA); + Log.i(TAG, "pairingCode=" + pairingCode); + } else if (res.equals(AdbManager.WIRELESS_STATUS_CONNECTED)) { + int port = intent.getIntExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, 0); + Log.i(TAG, "port=" + port); + } + mAdbActionLatch.countDown(); + } + } + }; + + private void adoptShellPermissionIdentity() { + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .adoptShellPermissionIdentity(android.Manifest.permission.MANAGE_DEBUGGING); + } + + private void dropShellPermissionIdentity() { + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .dropShellPermissionIdentity(); + } + + @Test + public void testBroadcastReceiverWithPermissions() throws Exception { + adoptShellPermissionIdentity(); + final IAdbManager mAdbManager = IAdbManager.Stub.asInterface( + ServiceManager.getService(Context.ADB_SERVICE)); + IntentFilter intentFilter = + new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION); + intentFilter.addAction(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION); + intentFilter.addAction(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); + assertEquals("Context does not have MANAGE_DEBUGGING permission.", + mContext.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING), + PackageManager.PERMISSION_GRANTED); + try { + mContext.registerReceiver(mReceiver, intentFilter); + mAdbManager.enablePairingByPairingCode(); + if (!mAdbActionLatch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) { + fail("Receiver did not receive adb intent action within the timeout duration"); + } + } finally { + mContext.unregisterReceiver(mReceiver); + } + } + + @Test + public void testBroadcastReceiverWithoutPermissions() throws Exception { + adoptShellPermissionIdentity(); + final IAdbManager mAdbManager = IAdbManager.Stub.asInterface( + ServiceManager.getService(Context.ADB_SERVICE)); + IntentFilter intentFilter = + new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION); + intentFilter.addAction(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION); + intentFilter.addAction(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); + mAdbManager.enablePairingByPairingCode(); + + dropShellPermissionIdentity(); + assertEquals("Context has MANAGE_DEBUGGING permission.", + mContext.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING), + PackageManager.PERMISSION_DENIED); + try { + mContext.registerReceiver(mReceiver, intentFilter); + + if (mAdbActionLatch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) { + fail("Broadcast receiver received adb action intent without debug permissions"); + } + } finally { + mContext.unregisterReceiver(mReceiver); + } + } + /** * Runs an adb test with the provided configuration. * diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index d94fafc6a5bf..ce9530c196ef 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -701,8 +701,15 @@ public final class Call { */ public static final int PROPERTY_CROSS_SIM = 0x00004000; + /** + * Connection is a tethered external call. + * Indicates that the {@link Connection} is fixed on this device but the audio streams are + * re-routed to another device. + */ + public static final int PROPERTY_TETHERED_CALL = 0x00008000; + //****************************************************************************************** - // Next PROPERTY value: 0x00004000 + // Next PROPERTY value: 0x00010000 //****************************************************************************************** private final @CallState int mState; @@ -899,6 +906,9 @@ public final class Call { if (hasProperty(properties, PROPERTY_CROSS_SIM)) { builder.append(" PROPERTY_CROSS_SIM"); } + if (hasProperty(properties, PROPERTY_TETHERED_CALL)) { + builder.append(" PROPERTY_TETHERED_CALL"); + } builder.append("]"); return builder.toString(); } diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java index fccdf76372dd..389df80497df 100644 --- a/telecomm/java/android/telecom/CallAudioState.java +++ b/telecomm/java/android/telecom/CallAudioState.java @@ -27,7 +27,6 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -42,7 +41,8 @@ import java.util.stream.Collectors; public final class CallAudioState implements Parcelable { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value={ROUTE_EARPIECE, ROUTE_BLUETOOTH, ROUTE_WIRED_HEADSET, ROUTE_SPEAKER}, + @IntDef(value = {ROUTE_EARPIECE, ROUTE_BLUETOOTH, ROUTE_WIRED_HEADSET, ROUTE_SPEAKER, + ROUTE_EXTERNAL}, flag=true) public @interface CallAudioRoute {} @@ -58,6 +58,9 @@ public final class CallAudioState implements Parcelable { /** Direct the audio stream through the device's speakerphone. */ public static final int ROUTE_SPEAKER = 0x00000008; + /** Direct the audio stream through another device. */ + public static final int ROUTE_EXTERNAL = 0x00000010; + /** * Direct the audio stream through the device's earpiece or wired headset if one is * connected. @@ -70,7 +73,7 @@ public final class CallAudioState implements Parcelable { * @hide **/ public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET | - ROUTE_SPEAKER; + ROUTE_SPEAKER | ROUTE_EXTERNAL; private final boolean isMuted; private final int route; @@ -189,7 +192,11 @@ public final class CallAudioState implements Parcelable { */ @CallAudioRoute public int getSupportedRouteMask() { - return supportedRouteMask; + if (route == ROUTE_EXTERNAL) { + return ROUTE_EXTERNAL; + } else { + return supportedRouteMask; + } } /** @@ -233,6 +240,10 @@ public final class CallAudioState implements Parcelable { listAppend(buffer, "SPEAKER"); } + if ((route & ROUTE_EXTERNAL) == ROUTE_EXTERNAL) { + listAppend(buffer, "EXTERNAL"); + } + return buffer.toString(); } diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 21a180459978..30d495942ece 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -561,6 +561,15 @@ public abstract class Connection extends Conferenceable { */ public static final int PROPERTY_CROSS_SIM = 1 << 13; + /** + * Connection is a tethered external call. + * <p> + * Indicates that the {@link Connection} is fixed on this device but the audio streams are + * re-routed to another device. + * <p> + */ + public static final int PROPERTY_TETHERED_CALL = 1 << 14; + //********************************************************************************************** // Next PROPERTY value: 1<<14 //********************************************************************************************** diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java index c8b8ffb9846b..326f4171de3b 100644 --- a/telephony/java/android/telephony/NetworkScanRequest.java +++ b/telephony/java/android/telephony/NetworkScanRequest.java @@ -221,7 +221,8 @@ public final class NetworkScanRequest implements Parcelable { private NetworkScanRequest(Parcel in) { mScanType = in.readInt(); - Parcelable[] tempSpecifiers = in.readParcelableArray(Object.class.getClassLoader()); + Parcelable[] tempSpecifiers = in.readParcelableArray(Object.class.getClassLoader(), + RadioAccessSpecifier.class); if (tempSpecifiers != null) { mSpecifiers = new RadioAccessSpecifier[tempSpecifiers.length]; for (int i = 0; i < tempSpecifiers.length; i++) { diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 7e2d80eb871c..e6d7df34f755 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -851,7 +851,8 @@ public final class ImsCallProfile implements Parcelable { mHasKnownUserIntentEmergency = in.readBoolean(); mRestrictCause = in.readInt(); mCallerNumberVerificationStatus = in.readInt(); - Object[] accepted = in.readArray(RtpHeaderExtensionType.class.getClassLoader()); + Object[] accepted = in.readArray(RtpHeaderExtensionType.class.getClassLoader(), + RtpHeaderExtensionType.class); mAcceptedRtpHeaderExtensionTypes = Arrays.stream(accepted) .map(o -> (RtpHeaderExtensionType) o).collect(Collectors.toSet()); } diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp index 89757134f3a7..fbfbf68b30bb 100644 --- a/tools/aapt2/cmd/Compile_test.cpp +++ b/tools/aapt2/cmd/Compile_test.cpp @@ -19,12 +19,11 @@ #include "android-base/file.h" #include "android-base/stringprintf.h" #include "android-base/utf8.h" - +#include "format/proto/ProtoDeserialize.h" #include "io/StringStream.h" #include "io/ZipArchive.h" #include "java/AnnotationProcessor.h" #include "test/Test.h" -#include "format/proto/ProtoDeserialize.h" namespace aapt { @@ -59,55 +58,56 @@ TEST_F(CompilerTest, MultiplePeriods) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); const std::string kResDir = BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests", "CompileTest", "res"}); + const std::string kOutDir = testing::TempDir(); // Resource files without periods in the file name should not throw errors const std::string path0 = BuildPath({kResDir, "values", "values.xml"}); - const std::string path0_out = BuildPath({kResDir, "values_values.arsc.flat"}); + const std::string path0_out = BuildPath({kOutDir, "values_values.arsc.flat"}); ::android::base::utf8::unlink(path0_out.c_str()); - ASSERT_EQ(TestCompile(path0, kResDir, /** legacy */ false, diag), 0); + ASSERT_EQ(TestCompile(path0, kOutDir, /** legacy */ false, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path0_out.c_str()), 0); - ASSERT_EQ(TestCompile(path0, kResDir, /** legacy */ true, diag), 0); + ASSERT_EQ(TestCompile(path0, kOutDir, /** legacy */ true, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path0_out.c_str()), 0); const std::string path1 = BuildPath({kResDir, "drawable", "image.png"}); - const std::string path1_out = BuildPath({kResDir, "drawable_image.png.flat"}); + const std::string path1_out = BuildPath({kOutDir, "drawable_image.png.flat"}); ::android::base::utf8::unlink(path1_out.c_str()); - ASSERT_EQ(TestCompile(path1, kResDir, /** legacy */ false, diag), 0); + ASSERT_EQ(TestCompile(path1, kOutDir, /** legacy */ false, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path1_out.c_str()), 0); - ASSERT_EQ(TestCompile(path1, kResDir, /** legacy */ true, diag), 0); + ASSERT_EQ(TestCompile(path1, kOutDir, /** legacy */ true, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path1_out.c_str()), 0); const std::string path2 = BuildPath({kResDir, "drawable", "image.9.png"}); - const std::string path2_out = BuildPath({kResDir, "drawable_image.9.png.flat"}); + const std::string path2_out = BuildPath({kOutDir, "drawable_image.9.png.flat"}); ::android::base::utf8::unlink(path2_out.c_str()); - ASSERT_EQ(TestCompile(path2, kResDir, /** legacy */ false, diag), 0); + ASSERT_EQ(TestCompile(path2, kOutDir, /** legacy */ false, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path2_out.c_str()), 0); - ASSERT_EQ(TestCompile(path2, kResDir, /** legacy */ true, diag), 0); + ASSERT_EQ(TestCompile(path2, kOutDir, /** legacy */ true, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path2_out.c_str()), 0); // Resource files with periods in the file name should fail on non-legacy compilations const std::string path3 = BuildPath({kResDir, "values", "values.all.xml"}); - const std::string path3_out = BuildPath({kResDir, "values_values.all.arsc.flat"}); + const std::string path3_out = BuildPath({kOutDir, "values_values.all.arsc.flat"}); ::android::base::utf8::unlink(path3_out.c_str()); - ASSERT_NE(TestCompile(path3, kResDir, /** legacy */ false, diag), 0); + ASSERT_NE(TestCompile(path3, kOutDir, /** legacy */ false, diag), 0); ASSERT_NE(::android::base::utf8::unlink(path3_out.c_str()), 0); - ASSERT_EQ(TestCompile(path3, kResDir, /** legacy */ true, diag), 0); + ASSERT_EQ(TestCompile(path3, kOutDir, /** legacy */ true, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path3_out.c_str()), 0); const std::string path4 = BuildPath({kResDir, "drawable", "image.small.png"}); - const std::string path4_out = BuildPath({kResDir, "drawable_image.small.png.flat"}); + const std::string path4_out = BuildPath({kOutDir, "drawable_image.small.png.flat"}); ::android::base::utf8::unlink(path4_out.c_str()); - ASSERT_NE(TestCompile(path4, kResDir, /** legacy */ false, diag), 0); + ASSERT_NE(TestCompile(path4, kOutDir, /** legacy */ false, diag), 0); ASSERT_NE(::android::base::utf8::unlink(path4_out.c_str()), 0); - ASSERT_EQ(TestCompile(path4, kResDir, /** legacy */ true, diag), 0); + ASSERT_EQ(TestCompile(path4, kOutDir, /** legacy */ true, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path4_out.c_str()), 0); const std::string path5 = BuildPath({kResDir, "drawable", "image.small.9.png"}); - const std::string path5_out = BuildPath({kResDir, "drawable_image.small.9.png.flat"}); + const std::string path5_out = BuildPath({kOutDir, "drawable_image.small.9.png.flat"}); ::android::base::utf8::unlink(path5_out.c_str()); - ASSERT_NE(TestCompile(path5, kResDir, /** legacy */ false, diag), 0); + ASSERT_NE(TestCompile(path5, kOutDir, /** legacy */ false, diag), 0); ASSERT_NE(::android::base::utf8::unlink(path5_out.c_str()), 0); - ASSERT_EQ(TestCompile(path5, kResDir, /** legacy */ true, diag), 0); + ASSERT_EQ(TestCompile(path5, kOutDir, /** legacy */ true, diag), 0); ASSERT_EQ(::android::base::utf8::unlink(path5_out.c_str()), 0); } @@ -116,9 +116,7 @@ TEST_F(CompilerTest, DirInput) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); const std::string kResDir = BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests", "CompileTest", "DirInput", "res"}); - const std::string kOutputFlata = - BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests", - "CompileTest", "DirInput", "compiled.flata"}); + const std::string kOutputFlata = BuildPath({testing::TempDir(), "compiled.flata"}); ::android::base::utf8::unlink(kOutputFlata.c_str()); std::vector<android::StringPiece> args; @@ -147,9 +145,7 @@ TEST_F(CompilerTest, ZipInput) { const std::string kResZip = BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests", "CompileTest", "ZipInput", "res.zip"}); - const std::string kOutputFlata = - BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests", - "CompileTest", "ZipInput", "compiled.flata"}); + const std::string kOutputFlata = BuildPath({testing::TempDir(), "compiled.flata"}); ::android::base::utf8::unlink(kOutputFlata.c_str()); @@ -257,9 +253,9 @@ TEST_F(CompilerTest, DoNotTranslateTest) { TEST_F(CompilerTest, RelativePathTest) { StdErrDiagnostics diag; - const std::string res_path = BuildPath( - {android::base::Dirname(android::base::GetExecutablePath()), - "integration-tests", "CompileTest", "res"}); + const std::string res_path = + BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests", + "CompileTest", "res"}); const std::string path_values_colors = GetTestPath("values/colors.xml"); WriteFile(path_values_colors, "<resources>" @@ -272,9 +268,8 @@ TEST_F(CompilerTest, RelativePathTest) { "<TextBox android:id=\"@+id/text_one\" android:background=\"@color/color_one\"/>" "</LinearLayout>"); - const std::string compiled_files_dir = BuildPath( - {android::base::Dirname(android::base::GetExecutablePath()), - "integration-tests", "CompileTest", "compiled"}); + const std::string compiled_files_dir = + BuildPath({testing::TempDir(), "integration-tests", "CompileTest", "compiled"}); CHECK(file::mkdirs(compiled_files_dir.data())); const std::string path_values_colors_out = @@ -283,9 +278,8 @@ TEST_F(CompilerTest, RelativePathTest) { BuildPath({compiled_files_dir, "layout_layout_one.flat"}); ::android::base::utf8::unlink(path_values_colors_out.c_str()); ::android::base::utf8::unlink(path_layout_layout_one_out.c_str()); - const std::string apk_path = BuildPath( - {android::base::Dirname(android::base::GetExecutablePath()), - "integration-tests", "CompileTest", "out.apk"}); + const std::string apk_path = + BuildPath({testing::TempDir(), "integration-tests", "CompileTest", "out.apk"}); const std::string source_set_res = BuildPath({"main", "res"}); const std::string relative_path_values_colors = diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp index e2f71dc45075..ddc1853ca13c 100644 --- a/tools/aapt2/test/Fixture.cpp +++ b/tools/aapt2/test/Fixture.cpp @@ -67,8 +67,7 @@ void ClearDirectory(const android::StringPiece& path) { } void TestDirectoryFixture::SetUp() { - temp_dir_ = file::BuildPath({android::base::GetExecutableDirectory(), - "_temp", + temp_dir_ = file::BuildPath({testing::TempDir(), "_temp", testing::UnitTest::GetInstance()->current_test_case()->name(), testing::UnitTest::GetInstance()->current_test_info()->name()}); ASSERT_TRUE(file::mkdirs(temp_dir_)); @@ -236,4 +235,4 @@ std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) { return args_; } -} // namespace aapt
\ No newline at end of file +} // namespace aapt |