diff options
86 files changed, 1975 insertions, 782 deletions
diff --git a/Android.bp b/Android.bp index c8789bf0405c..172b2fccc1e2 100644 --- a/Android.bp +++ b/Android.bp @@ -768,6 +768,24 @@ java_library { dxflags: ["--core-library"], } +// ==== java proto host library ============================== +java_library_host { + name: "platformprotos", + srcs: [ + "cmds/am/proto/instrumentation_data.proto", + "core/proto/**/*.proto", + "libs/incident/proto/**/*.proto", + "cmds/statsd/src/**/*.proto", + ], + proto: { + include_dirs: ["external/protobuf/src"], + type: "full", + }, + errorprone: { + javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520 + }, +} + // ==== c++ proto device library ============================== cc_library { name: "libplatformprotos", @@ -1207,11 +1225,6 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x doc_defaults { name: "metalava-framework-docs-default", srcs: [ - // test mock src files. - "test-mock/src/android/test/mock/**/*.java", - // test runner excluding mock src files. - "test-runner/src/**/*.java", - "test-base/src/**/*.java", ":opt-telephony-srcs", ":opt-net-voip-srcs", ":openjdk_javadoc_files", diff --git a/Android.mk b/Android.mk index c68eb46ce05d..031809ce2196 100644 --- a/Android.mk +++ b/Android.mk @@ -670,23 +670,6 @@ LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk include $(BUILD_DROIDDOC) -# ==== java proto host library ============================== -include $(CLEAR_VARS) -LOCAL_MODULE := platformprotos -LOCAL_PROTOC_OPTIMIZE_TYPE := full -LOCAL_PROTOC_FLAGS := \ - -Iexternal/protobuf/src -LOCAL_SOURCE_FILES_ALL_GENERATED := true -LOCAL_SRC_FILES := \ - cmds/am/proto/instrumentation_data.proto \ - cmds/statsd/src/perfetto/perfetto_config.proto \ - $(call all-proto-files-under, core/proto) \ - $(call all-proto-files-under, libs/incident/proto) \ - $(call all-proto-files-under, cmds/statsd/src) -# b/72714520 -LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF -include $(BUILD_HOST_JAVA_LIBRARY) - # ==== java proto device library (for test only) ============================== include $(CLEAR_VARS) LOCAL_MODULE := platformprotosnano diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index fda4f4bb2363..cbbe91574ef7 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -137,6 +137,7 @@ Landroid/app/ActivityManager$StackInfo;->userId:I Landroid/app/ActivityManager$StackInfo;->visible:Z Landroid/app/ActivityManager$TaskDescription;->getBackgroundColor()I Landroid/app/ActivityManager$TaskDescription;->getInMemoryIcon()Landroid/graphics/Bitmap; +Landroid/app/ActivityManager$TaskDescription;->setIcon(Landroid/graphics/Bitmap;)V Landroid/app/ActivityManager$TaskSnapshot;->getContentInsets()Landroid/graphics/Rect; Landroid/app/ActivityManager$TaskSnapshot;->getOrientation()I Landroid/app/ActivityManager$TaskSnapshot;->getScale()F @@ -904,6 +905,7 @@ Landroid/app/ResultInfo;->mResultWho:Ljava/lang/String; Landroid/app/SearchableInfo$ActionKeyInfo;->getQueryActionMsg()Ljava/lang/String; Landroid/app/SearchableInfo$ActionKeyInfo;->getSuggestActionMsg()Ljava/lang/String; Landroid/app/SearchableInfo$ActionKeyInfo;->getSuggestActionMsgColumn()Ljava/lang/String; +Landroid/app/SearchableInfo;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;Landroid/content/ComponentName;)V Landroid/app/SearchableInfo;->findActionKey(I)Landroid/app/SearchableInfo$ActionKeyInfo; Landroid/app/SearchableInfo;->getActivityContext(Landroid/content/Context;)Landroid/content/Context; Landroid/app/SearchableInfo;->getIconId()I @@ -1243,6 +1245,7 @@ Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth Landroid/bluetooth/IBluetooth$Stub;-><init>()V Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth; Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I +Landroid/bluetooth/IBluetooth;->fetchRemoteUuids(Landroid/bluetooth/BluetoothDevice;)Z Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String; Landroid/bluetooth/IBluetooth;->getRemoteAlias(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String; Landroid/bluetooth/IBluetooth;->isEnabled()Z @@ -1514,8 +1517,11 @@ Landroid/content/pm/IPackageInstallObserver2$Stub;->asInterface(Landroid/os/IBin Landroid/content/pm/IPackageInstallObserver2;->onPackageInstalled(Ljava/lang/String;ILjava/lang/String;Landroid/os/Bundle;)V Landroid/content/pm/IPackageInstallObserver2;->onUserActionRequired(Landroid/content/Intent;)V Landroid/content/pm/IPackageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Landroid/content/pm/IPackageManager$Stub$Proxy;->checkUidPermission(Ljava/lang/String;I)I +Landroid/content/pm/IPackageManager$Stub$Proxy;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String; Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice; Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstallLocation()I +Landroid/content/pm/IPackageManager$Stub$Proxy;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo; Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo; Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String; Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String; @@ -1534,6 +1540,7 @@ Landroid/content/pm/IPackageManager;->currentToCanonicalPackageNames([Ljava/lang Landroid/content/pm/IPackageManager;->deleteApplicationCacheFiles(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)V Landroid/content/pm/IPackageManager;->enterSafeMode()V Landroid/content/pm/IPackageManager;->getApplicationEnabledSetting(Ljava/lang/String;I)I +Landroid/content/pm/IPackageManager;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String; Landroid/content/pm/IPackageManager;->getBlockUninstallForUser(Ljava/lang/String;I)Z Landroid/content/pm/IPackageManager;->getComponentEnabledSetting(Landroid/content/ComponentName;I)I Landroid/content/pm/IPackageManager;->getFlagsForUid(I)I @@ -1745,6 +1752,7 @@ Landroid/content/pm/PackageParser;-><init>()V Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V Landroid/content/pm/PackageParser;->generateActivityInfo(Landroid/content/pm/PackageParser$Activity;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ActivityInfo; +Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;)Landroid/content/pm/ApplicationInfo; Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ApplicationInfo; Landroid/content/pm/PackageParser;->generateInstrumentationInfo(Landroid/content/pm/PackageParser$Instrumentation;I)Landroid/content/pm/InstrumentationInfo; Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;)Landroid/content/pm/PackageInfo; @@ -1756,6 +1764,7 @@ Landroid/content/pm/PackageParser;->generateServiceInfo(Landroid/content/pm/Pack Landroid/content/pm/PackageParser;->mCallback:Landroid/content/pm/PackageParser$Callback; Landroid/content/pm/PackageParser;->NEW_PERMISSIONS:[Landroid/content/pm/PackageParser$NewPermissionInfo; Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package; @@ -1803,6 +1812,7 @@ Landroid/content/pm/UserInfo;->serialNumber:I Landroid/content/pm/VerifierInfo;-><init>(Ljava/lang/String;Ljava/security/PublicKey;)V Landroid/content/pm/XmlSerializerAndParser;->createFromXml(Lorg/xmlpull/v1/XmlPullParser;)Ljava/lang/Object; Landroid/content/pm/XmlSerializerAndParser;->writeAsXml(Ljava/lang/Object;Lorg/xmlpull/v1/XmlSerializer;)V +Landroid/content/res/ApkAssets;->getAssetPath()Ljava/lang/String; Landroid/content/res/AssetFileDescriptor;->mFd:Landroid/os/ParcelFileDescriptor; Landroid/content/res/AssetFileDescriptor;->mLength:J Landroid/content/res/AssetFileDescriptor;->mStartOffset:J @@ -1814,6 +1824,7 @@ Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/Strin Landroid/content/res/AssetManager;->addOverlayPath(Ljava/lang/String;)I Landroid/content/res/AssetManager;->applyStyle(JIILandroid/content/res/XmlBlock$Parser;[IJJ)V Landroid/content/res/AssetManager;->createTheme()J +Landroid/content/res/AssetManager;->getApkAssets()[Landroid/content/res/ApkAssets; Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray; Landroid/content/res/AssetManager;->getGlobalAssetCount()I Landroid/content/res/AssetManager;->getGlobalAssetManagerCount()I @@ -1837,6 +1848,7 @@ Landroid/content/res/AssetManager;->retrieveAttributes(Landroid/content/res/XmlB Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V Landroid/content/res/AssetManager;->sSystem:Landroid/content/res/AssetManager; Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V +Landroid/content/res/ColorStateList;-><init>()V Landroid/content/res/ColorStateList;->canApplyTheme()Z Landroid/content/res/ColorStateList;->getColors()[I Landroid/content/res/ColorStateList;->getStates()[[I @@ -1899,6 +1911,7 @@ Landroid/content/res/Resources;->setImpl(Landroid/content/res/ResourcesImpl;)V Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager; +Landroid/content/res/ResourcesImpl;->getDisplayMetrics()Landroid/util/DisplayMetrics; Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object; Landroid/content/res/ResourcesImpl;->mAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache; @@ -2158,6 +2171,7 @@ Landroid/graphics/CanvasProperty;->createFloat(F)Landroid/graphics/CanvasPropert Landroid/graphics/CanvasProperty;->createPaint(Landroid/graphics/Paint;)Landroid/graphics/CanvasProperty; Landroid/graphics/ColorMatrixColorFilter;->mMatrix:Landroid/graphics/ColorMatrix; Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V +Landroid/graphics/ColorMatrixColorFilter;->setColorMatrixArray([F)V Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V Landroid/graphics/drawable/AnimatedRotateDrawable;->setFramesCount(I)V Landroid/graphics/drawable/AnimatedRotateDrawable;->setFramesDuration(I)V @@ -4189,6 +4203,7 @@ Landroid/os/SELinux;->isSELinuxEnforced()Z Landroid/os/SELinux;->restoreconRecursive(Ljava/io/File;)Z Landroid/os/ServiceManager;-><init>()V Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V +Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;Z)V Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V Landroid/os/ServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder; Landroid/os/ServiceManager;->getIServiceManager()Landroid/os/IServiceManager; @@ -4273,6 +4288,7 @@ Landroid/os/storage/VolumeInfo;->getDisk()Landroid/os/storage/DiskInfo; Landroid/os/storage/VolumeInfo;->getDiskId()Ljava/lang/String; Landroid/os/storage/VolumeInfo;->getEnvironmentForState(I)Ljava/lang/String; Landroid/os/storage/VolumeInfo;->getFsUuid()Ljava/lang/String; +Landroid/os/storage/VolumeInfo;->getInternalPath()Ljava/io/File; Landroid/os/storage/VolumeInfo;->getInternalPathForUser(I)Ljava/io/File; Landroid/os/storage/VolumeInfo;->getMountUserId()I Landroid/os/storage/VolumeInfo;->getPath()Ljava/io/File; @@ -4308,6 +4324,7 @@ Landroid/os/StrictMode;->onWebViewMethodCalledOnWrongThread(Ljava/lang/Throwable Landroid/os/StrictMode;->sLastVmViolationTime:Ljava/util/HashMap; Landroid/os/StrictMode;->sWindowManager:Landroid/util/Singleton; Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal; +Landroid/os/SystemClock;-><init>()V Landroid/os/SystemClock;->currentThreadTimeMicro()J Landroid/os/SystemClock;->currentTimeMicro()J Landroid/os/SystemProperties;-><init>()V @@ -4393,6 +4410,7 @@ Landroid/os/UserManager;->getUserSerialNumber(I)I Landroid/os/UserManager;->getUserStartRealtime()J Landroid/os/UserManager;->getUserUnlockRealtime()J Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z +Landroid/os/UserManager;->isDeviceInDemoMode(Landroid/content/Context;)Z Landroid/os/UserManager;->isGuestUser(I)Z Landroid/os/UserManager;->isLinkedUser()Z Landroid/os/UserManager;->isUserAdmin(I)Z @@ -4598,6 +4616,7 @@ Landroid/provider/Settings$Global;->ZEN_MODE_CONFIG_ETAG:Ljava/lang/String; Landroid/provider/Settings$Global;->ZEN_MODE_IMPORTANT_INTERRUPTIONS:I Landroid/provider/Settings$Global;->ZEN_MODE_NO_INTERRUPTIONS:I Landroid/provider/Settings$Global;->ZEN_MODE_OFF:I +Landroid/provider/Settings$NameValueCache;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String; Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder; Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String; Landroid/provider/Settings$Secure;->ACCESSIBILITY_CAPTIONING_TYPEFACE:Ljava/lang/String; @@ -4636,10 +4655,12 @@ Landroid/provider/Settings$Secure;->SELECTED_SPELL_CHECKER_SUBTYPE:Ljava/lang/St Landroid/provider/Settings$Secure;->SETTINGS_TO_BACKUP:[Ljava/lang/String; Landroid/provider/Settings$Secure;->SMS_DEFAULT_APPLICATION:Ljava/lang/String; Landroid/provider/Settings$Secure;->sNameValueCache:Landroid/provider/Settings$NameValueCache; +Landroid/provider/Settings$Secure;->sProviderHolder:Landroid/provider/Settings$ContentProviderHolder; Landroid/provider/Settings$Secure;->VOICE_RECOGNITION_SERVICE:Ljava/lang/String; Landroid/provider/Settings$System;->AIRPLANE_MODE_TOGGLEABLE_RADIOS:Ljava/lang/String; Landroid/provider/Settings$System;->CAR_DOCK_SOUND:Ljava/lang/String; Landroid/provider/Settings$System;->CAR_UNDOCK_SOUND:Ljava/lang/String; +Landroid/provider/Settings$System;->CLONE_TO_MANAGED_PROFILE:Ljava/util/Set; Landroid/provider/Settings$System;->DESK_DOCK_SOUND:Ljava/lang/String; Landroid/provider/Settings$System;->DESK_UNDOCK_SOUND:Ljava/lang/String; Landroid/provider/Settings$System;->DOCK_SOUNDS_ENABLED:Ljava/lang/String; @@ -4651,6 +4672,9 @@ Landroid/provider/Settings$System;->HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY: Landroid/provider/Settings$System;->LOCKSCREEN_SOUNDS_ENABLED:Ljava/lang/String; Landroid/provider/Settings$System;->LOCK_SOUND:Ljava/lang/String; Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String; +Landroid/provider/Settings$System;->MOVED_TO_GLOBAL:Ljava/util/HashSet; +Landroid/provider/Settings$System;->MOVED_TO_SECURE:Ljava/util/HashSet; +Landroid/provider/Settings$System;->MOVED_TO_SECURE_THEN_GLOBAL:Ljava/util/HashSet; Landroid/provider/Settings$System;->NOTIFICATION_LIGHT_PULSE:Ljava/lang/String; Landroid/provider/Settings$System;->POINTER_LOCATION:Ljava/lang/String; Landroid/provider/Settings$System;->POINTER_SPEED:Ljava/lang/String; @@ -4665,6 +4689,7 @@ Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$N Landroid/provider/Settings$System;->sProviderHolder:Landroid/provider/Settings$ContentProviderHolder; Landroid/provider/Settings$System;->TTY_MODE:Ljava/lang/String; Landroid/provider/Settings$System;->UNLOCK_SOUND:Ljava/lang/String; +Landroid/provider/Settings$System;->VALIDATORS:Ljava/util/Map; Landroid/provider/Settings$System;->VIBRATE_IN_SILENT:Ljava/lang/String; Landroid/provider/Settings;->ACTION_TRUSTED_CREDENTIALS_USER:Ljava/lang/String; Landroid/provider/Settings;->ACTION_USER_DICTIONARY_INSERT:Ljava/lang/String; @@ -5408,6 +5433,7 @@ Landroid/telephony/ServiceState;->mCdmaEriIconMode:I Landroid/telephony/ServiceState;->mCdmaRoamingIndicator:I Landroid/telephony/ServiceState;->mCssIndicator:Z Landroid/telephony/ServiceState;->mIsManualNetworkSelection:Z +Landroid/telephony/ServiceState;->mIsUsingCarrierAggregation:Z Landroid/telephony/ServiceState;->mNetworkId:I Landroid/telephony/ServiceState;->mSystemId:I Landroid/telephony/ServiceState;->newFromBundle(Landroid/os/Bundle;)Landroid/telephony/ServiceState; @@ -5773,6 +5799,7 @@ Landroid/transition/Scene;->mExitAction:Ljava/lang/Runnable; Landroid/transition/Scene;->setCurrentScene(Landroid/view/View;Landroid/transition/Scene;)V Landroid/transition/Transition;->cancel()V Landroid/transition/Transition;->end()V +Landroid/transition/Transition;->getRunningAnimators()Landroid/util/ArrayMap; Landroid/transition/TransitionManager;->getRunningTransitions()Landroid/util/ArrayMap; Landroid/transition/TransitionManager;->sPendingTransitions:Ljava/util/ArrayList; Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal; @@ -6220,6 +6247,7 @@ Landroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/ Landroid/view/SurfaceControl;->HIDDEN:I Landroid/view/SurfaceControl;->hide()V Landroid/view/SurfaceControl;->openTransaction()V +Landroid/view/SurfaceControl;->screenshot(Landroid/graphics/Rect;III)Landroid/graphics/Bitmap; Landroid/view/SurfaceControl;->screenshot(Landroid/graphics/Rect;IIIIZI)Landroid/graphics/Bitmap; Landroid/view/SurfaceControl;->screenshot(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V Landroid/view/SurfaceControl;->setDisplayLayerStack(Landroid/os/IBinder;I)V @@ -7013,6 +7041,7 @@ Landroid/widget/ListView;->fillDown(II)Landroid/view/View; Landroid/widget/ListView;->fillSpecific(II)Landroid/view/View; Landroid/widget/ListView;->fillUp(II)Landroid/view/View; Landroid/widget/ListView;->getHeightForPosition(I)I +Landroid/widget/ListView;->isDirectChildHeaderOrFooter(Landroid/view/View;)Z Landroid/widget/ListView;->makeAndAddView(IIZIZ)Landroid/view/View; Landroid/widget/ListView;->mAreAllItemsSelectable:Z Landroid/widget/ListView;->mDivider:Landroid/graphics/drawable/Drawable; @@ -7561,6 +7590,7 @@ Lcom/android/internal/appwidget/IAppWidgetService$Stub;->TRANSACTION_bindAppWidg Lcom/android/internal/appwidget/IAppWidgetService;->bindAppWidgetId(Ljava/lang/String;IILandroid/content/ComponentName;Landroid/os/Bundle;)Z Lcom/android/internal/appwidget/IAppWidgetService;->bindRemoteViewsService(Ljava/lang/String;ILandroid/content/Intent;Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/app/IServiceConnection;I)Z Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I +Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews; Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V Lcom/android/internal/backup/IBackupTransport$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/backup/IBackupTransport; Lcom/android/internal/backup/IBackupTransport;->clearBackupData(Landroid/content/pm/PackageInfo;)I @@ -7777,6 +7807,9 @@ Lcom/android/internal/R$attr;->switchStyle:I Lcom/android/internal/R$attr;->text:I Lcom/android/internal/R$attr;->title:I Lcom/android/internal/R$attr;->webViewStyle:I +Lcom/android/internal/R$bool;-><init>()V +Lcom/android/internal/R$bool;->config_automatic_brightness_available:I +Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I Lcom/android/internal/R$bool;->config_showNavigationBar:I Lcom/android/internal/R$dimen;-><init>()V @@ -8200,6 +8233,8 @@ Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I Lcom/android/internal/R$styleable;->Window:[I Lcom/android/internal/R$styleable;->WindowAnimation:[I Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I +Lcom/android/internal/R$styleable;->Window_windowBackground:I +Lcom/android/internal/R$styleable;->Window_windowFullscreen:I Lcom/android/internal/R$styleable;->Window_windowIsFloating:I Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I @@ -8269,6 +8304,7 @@ Lcom/android/internal/telephony/IPhoneStateListener;->onServiceStateChanged(Land Lcom/android/internal/telephony/IPhoneStateListener;->onSignalStrengthChanged(I)V Lcom/android/internal/telephony/IPhoneStateListener;->onSignalStrengthsChanged(Landroid/telephony/SignalStrength;)V Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String; Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo; Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->TRANSACTION_getDeviceId:I @@ -8454,6 +8490,8 @@ Lcom/android/internal/view/menu/MenuBuilder;->addMenuPresenter(Lcom/android/inte Lcom/android/internal/view/menu/MenuBuilder;->addMenuPresenter(Lcom/android/internal/view/menu/MenuPresenter;Landroid/content/Context;)V Lcom/android/internal/view/menu/MenuBuilder;->collapseItemActionView(Lcom/android/internal/view/menu/MenuItemImpl;)Z Lcom/android/internal/view/menu/MenuBuilder;->getContext()Landroid/content/Context; +Lcom/android/internal/view/menu/MenuBuilder;->getHeaderIcon()Landroid/graphics/drawable/Drawable; +Lcom/android/internal/view/menu/MenuBuilder;->getHeaderTitle()Ljava/lang/CharSequence; Lcom/android/internal/view/menu/MenuBuilder;->getNonActionItems()Ljava/util/ArrayList; Lcom/android/internal/view/menu/MenuBuilder;->getRootMenu()Lcom/android/internal/view/menu/MenuBuilder; Lcom/android/internal/view/menu/MenuBuilder;->getVisibleItems()Ljava/util/ArrayList; @@ -8471,11 +8509,14 @@ Lcom/android/internal/view/menu/MenuItemImpl;->mIconResId:I Lcom/android/internal/view/menu/MenuItemImpl;->requestsActionButton()Z Lcom/android/internal/view/menu/MenuItemImpl;->requiresActionButton()Z Lcom/android/internal/view/menu/MenuItemImpl;->setActionViewExpanded(Z)V +Lcom/android/internal/view/menu/MenuItemImpl;->setExclusiveCheckable(Z)V Lcom/android/internal/view/menu/MenuItemImpl;->setMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V Lcom/android/internal/view/menu/MenuPopupHelper;-><init>(Landroid/content/Context;Lcom/android/internal/view/menu/MenuBuilder;)V Lcom/android/internal/view/menu/MenuPopupHelper;-><init>(Landroid/content/Context;Lcom/android/internal/view/menu/MenuBuilder;Landroid/view/View;)V Lcom/android/internal/view/menu/MenuPopupHelper;->dismiss()V +Lcom/android/internal/view/menu/MenuPopupHelper;->getPopup()Lcom/android/internal/view/menu/MenuPopup; Lcom/android/internal/view/menu/MenuPopupHelper;->mForceShowIcon:Z +Lcom/android/internal/view/menu/MenuPopupHelper;->setAnchorView(Landroid/view/View;)V Lcom/android/internal/view/menu/MenuPopupHelper;->setForceShowIcon(Z)V Lcom/android/internal/view/menu/MenuPopupHelper;->setGravity(I)V Lcom/android/internal/view/menu/MenuPopupHelper;->show()V @@ -8802,6 +8843,7 @@ Ljava/lang/reflect/Field;->accessFlags:I Ljava/lang/reflect/Field;->getOffset()I Ljava/lang/reflect/Parameter;-><init>(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V Ljava/lang/reflect/Proxy;->invoke(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; +Ljava/lang/Runtime;-><init>()V Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V Ljava/lang/Runtime;->loadLibrary0(Ljava/lang/ClassLoader;Ljava/lang/String;)V @@ -9170,6 +9212,7 @@ Lorg/xml/sax/helpers/NamespaceSupport;->contextPos:I Lorg/xml/sax/helpers/NamespaceSupport;->contexts:[Lorg/xml/sax/helpers/NamespaceSupport$Context; Lorg/xml/sax/helpers/NamespaceSupport;->currentContext:Lorg/xml/sax/helpers/NamespaceSupport$Context; Lorg/xml/sax/helpers/NamespaceSupport;->EMPTY_ENUMERATION:Ljava/util/Enumeration; +Lorg/xml/sax/helpers/NamespaceSupport;->namespaceDeclUris:Z Lorg/xml/sax/helpers/ParserAdapter;->attAdapter:Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter; Lorg/xml/sax/helpers/ParserAdapter;->atts:Lorg/xml/sax/helpers/AttributesImpl; Lorg/xml/sax/helpers/ParserAdapter;->checkNotParsing(Ljava/lang/String;Ljava/lang/String;)V @@ -9189,6 +9232,7 @@ Lorg/xml/sax/helpers/ParserAdapter;->processName(Ljava/lang/String;ZZ)[Ljava/lan Lorg/xml/sax/helpers/ParserAdapter;->reportError(Ljava/lang/String;)V Lorg/xml/sax/helpers/ParserAdapter;->setup(Lorg/xml/sax/Parser;)V Lorg/xml/sax/helpers/ParserAdapter;->setupParser()V +Lorg/xml/sax/helpers/ParserAdapter;->uris:Z Lorg/xml/sax/helpers/XMLFilterImpl;->contentHandler:Lorg/xml/sax/ContentHandler; Lorg/xml/sax/helpers/XMLFilterImpl;->dtdHandler:Lorg/xml/sax/DTDHandler; Lorg/xml/sax/helpers/XMLFilterImpl;->entityResolver:Lorg/xml/sax/EntityResolver; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 1ea93a419113..c22a43ec4af3 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2767,7 +2767,6 @@ public class Notification implements Parcelable */ private void fixDuplicateExtras() { if (extras != null) { - fixDuplicateExtra(mSmallIcon, EXTRA_SMALL_ICON); fixDuplicateExtra(mLargeIcon, EXTRA_LARGE_ICON); } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 22367b21221a..ff38c1f37007 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9398,9 +9398,9 @@ public class DevicePolicyManager { * <ul> * <li>{@link ApnSetting#getOperatorNumeric()}</li> * <li>{@link ApnSetting#getApnName()}</li> - * <li>{@link ApnSetting#getProxyAddress()}</li> + * <li>{@link ApnSetting#getProxyAddressAsString()}</li> * <li>{@link ApnSetting#getProxyPort()}</li> - * <li>{@link ApnSetting#getMmsProxyAddress()}</li> + * <li>{@link ApnSetting#getMmsProxyAddressAsString()}</li> * <li>{@link ApnSetting#getMmsProxyPort()}</li> * <li>{@link ApnSetting#getMmsc()}</li> * <li>{@link ApnSetting#isEnabled()}</li> diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 87c64cd12903..32c6898e8c00 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2365,13 +2365,25 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, is defined relative to the active array rectangle given in * this field, with <code>(0, 0)</code> being the top-left of this rectangle.</p> * <p>The active array may be smaller than the full pixel array, since the full array may - * include black calibration pixels or other inactive regions, and geometric correction - * resulting in scaling or cropping may have been applied.</p> + * include black calibration pixels or other inactive regions.</p> + * <p>For devices that do not support {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the active + * array must be the same as {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</p> + * <p>For devices that support {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the active array must + * be enclosed by {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. The difference between + * pre-correction active array and active array accounts for scaling or cropping caused + * by lens geometric distortion correction.</p> + * <p>In general, application should always refer to active array size for controls like + * metering regions or crop region. Two exceptions are when the application is dealing with + * RAW image buffers (RAW_SENSOR, RAW10, RAW12 etc), or when application explicitly set + * {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} to OFF. In these cases, application should refer + * to {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</p> * <p><b>Units</b>: Pixel coordinates on the image sensor</p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE = @@ -2616,9 +2628,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <ol> * <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}.</li> * </ol> - * <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same - * as the post-distortion-corrected rectangle given in - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> + * <p>If the camera device doesn't support geometric distortion correction, or all of the + * geometric distortion fields are no-ops, this rectangle will be the same as the + * post-distortion-corrected rectangle given in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> * <p>This rectangle is defined relative to the full pixel array; (0,0) is the top-left of * the full pixel array, and the size of the full pixel array is given by * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p> diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 411a97e3eca4..aca77a5be47e 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1269,11 +1269,26 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * Otherwise will always be present.</p> * <p>The maximum number of regions supported by the device is determined by the value * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe}.</p> - * <p>The coordinate system is based on the active pixel array, - * with (0,0) being the top-left pixel in the active pixel array, and + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being + * the top-left pixel in the active pixel array, and * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the - * bottom-right pixel in the active pixel array.</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right + * pixel in the pre-correction active pixel array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight * for every pixel in the area. This means that a large metering area * with the same weight as a smaller area will have more effect in @@ -1289,15 +1304,20 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * region and output only the intersection rectangle as the metering region in the result * metadata. If the region is entirely outside the crop region, it will be ignored and * not reported in the result metadata.</p> - * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on + * distortion correction capability and mode</p> * <p><b>Range of valid values:</b><br> * Coordinates must be between <code>[(0,0), (width, height))</code> of - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * depending on distortion correction capability and mode</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS = @@ -1443,11 +1463,26 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * Otherwise will always be present.</p> * <p>The maximum number of focus areas supported by the device is determined by the value * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf}.</p> - * <p>The coordinate system is based on the active pixel array, - * with (0,0) being the top-left pixel in the active pixel array, and + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being + * the top-left pixel in the active pixel array, and + * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right + * pixel in the pre-correction active pixel array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array, and * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the - * bottom-right pixel in the active pixel array.</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight * for every pixel in the area. This means that a large metering area * with the same weight as a smaller area will have more effect in @@ -1464,15 +1499,20 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * region and output only the intersection rectangle as the metering region in the result * metadata. If the region is entirely outside the crop region, it will be ignored and * not reported in the result metadata.</p> - * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on + * distortion correction capability and mode</p> * <p><b>Range of valid values:</b><br> * Coordinates must be between <code>[(0,0), (width, height))</code> of - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * depending on distortion correction capability and mode</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS = @@ -1612,11 +1652,26 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * Otherwise will always be present.</p> * <p>The maximum number of regions supported by the device is determined by the value * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb}.</p> - * <p>The coordinate system is based on the active pixel array, - * with (0,0) being the top-left pixel in the active pixel array, and + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being + * the top-left pixel in the active pixel array, and * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the - * bottom-right pixel in the active pixel array.</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right + * pixel in the pre-correction active pixel array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> * <p>The weight must range from 0 to 1000, and represents a weight * for every pixel in the area. This means that a large metering area * with the same weight as a smaller area will have more effect in @@ -1632,15 +1687,20 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * region and output only the intersection rectangle as the metering region in the result * metadata. If the region is entirely outside the crop region, it will be ignored and * not reported in the result metadata.</p> - * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on + * distortion correction capability and mode</p> * <p><b>Range of valid values:</b><br> * Coordinates must be between <code>[(0,0), (width, height))</code> of - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * depending on distortion correction capability and mode</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS = @@ -2433,9 +2493,17 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> /** * <p>The desired region of the sensor to read out for this capture.</p> * <p>This control can be used to implement digital zoom.</p> - * <p>The crop region coordinate system is based off - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the - * top-left corner of the sensor active array.</p> + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being + * the top-left pixel of the active array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array.</p> * <p>Output streams use this rectangle to produce their output, * cropping to a smaller region if necessary to maintain the * stream's aspect ratio, then scaling the sensor input to @@ -2454,20 +2522,30 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * outputs will crop horizontally (pillarbox), and 16:9 * streams will match exactly. These additional crops will * be centered within the crop region.</p> - * <p>The width and height of the crop region cannot - * be set to be smaller than + * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height + * of the crop region cannot be set to be smaller than * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p> + * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, the width + * and height of the crop region cannot be set to be smaller than + * <code>floor( preCorrectionActiveArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> + * and + * <code>floor( preCorrectionActiveArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, + * respectively.</p> * <p>The camera device may adjust the crop region to account * for rounding and other hardware requirements; the final * crop region used will be included in the output capture * result.</p> * <p><b>Units</b>: Pixel coordinates relative to - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction + * capability and mode</p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.graphics.Rect> SCALER_CROP_REGION = @@ -3186,15 +3264,14 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * any correction at all would slow down capture rate. Every output stream will have a * similar amount of enhancement applied.</p> * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not - * applied to any RAW output. Metadata coordinates such as face rectangles or metering + * applied to any RAW output. Metadata coordinates such as face rectangles or metering * regions are also not affected by correction.</p> - * <p>Applications enabling distortion correction need to pay extra attention when converting - * image coordinates between corrected output buffers and the sensor array. For example, if - * the app supports tap-to-focus and enables correction, it then has to apply the distortion - * model described in {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} to the image buffer tap coordinates to properly - * calculate the tap position on the sensor active array to be used with - * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}. The same applies in reverse to detected face rectangles if - * they need to be drawn on top of the corrected output buffers.</p> + * <p>This control will be on by default on devices that support this control. Applications + * disabling distortion correction need to pay extra attention with the coordinate system of + * metering regions, crop region, and face rectangles. When distortion correction is OFF, + * metadata coordinates follow the coordinate system of + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata + * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> * <p><b>Possible values:</b> * <ul> * <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li> @@ -3205,9 +3282,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * - * @see CaptureRequest#CONTROL_AF_REGIONS * @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES * @see CameraCharacteristics#LENS_DISTORTION + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE * @see #DISTORTION_CORRECTION_MODE_OFF * @see #DISTORTION_CORRECTION_MODE_FAST * @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 6439338428ee..75c27f56c0a6 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -730,11 +730,26 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * Otherwise will always be present.</p> * <p>The maximum number of regions supported by the device is determined by the value * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe}.</p> - * <p>The coordinate system is based on the active pixel array, - * with (0,0) being the top-left pixel in the active pixel array, and + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being + * the top-left pixel in the active pixel array, and * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the - * bottom-right pixel in the active pixel array.</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right + * pixel in the pre-correction active pixel array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight * for every pixel in the area. This means that a large metering area * with the same weight as a smaller area will have more effect in @@ -750,15 +765,20 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * region and output only the intersection rectangle as the metering region in the result * metadata. If the region is entirely outside the crop region, it will be ignored and * not reported in the result metadata.</p> - * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on + * distortion correction capability and mode</p> * <p><b>Range of valid values:</b><br> * Coordinates must be between <code>[(0,0), (width, height))</code> of - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * depending on distortion correction capability and mode</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS = @@ -1152,11 +1172,26 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * Otherwise will always be present.</p> * <p>The maximum number of focus areas supported by the device is determined by the value * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf}.</p> - * <p>The coordinate system is based on the active pixel array, - * with (0,0) being the top-left pixel in the active pixel array, and + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being + * the top-left pixel in the active pixel array, and + * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right + * pixel in the pre-correction active pixel array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array, and * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the - * bottom-right pixel in the active pixel array.</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight * for every pixel in the area. This means that a large metering area * with the same weight as a smaller area will have more effect in @@ -1173,15 +1208,20 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * region and output only the intersection rectangle as the metering region in the result * metadata. If the region is entirely outside the crop region, it will be ignored and * not reported in the result metadata.</p> - * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on + * distortion correction capability and mode</p> * <p><b>Range of valid values:</b><br> * Coordinates must be between <code>[(0,0), (width, height))</code> of - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * depending on distortion correction capability and mode</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS = @@ -1730,11 +1770,26 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * Otherwise will always be present.</p> * <p>The maximum number of regions supported by the device is determined by the value * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb}.</p> - * <p>The coordinate system is based on the active pixel array, - * with (0,0) being the top-left pixel in the active pixel array, and + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being + * the top-left pixel in the active pixel array, and + * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and + * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1, + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right + * pixel in the pre-correction active pixel array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array, and * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1, - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the - * bottom-right pixel in the active pixel array.</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the + * active pixel array.</p> * <p>The weight must range from 0 to 1000, and represents a weight * for every pixel in the area. This means that a large metering area * with the same weight as a smaller area will have more effect in @@ -1750,15 +1805,20 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * region and output only the intersection rectangle as the metering region in the result * metadata. If the region is entirely outside the crop region, it will be ignored and * not reported in the result metadata.</p> - * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on + * distortion correction capability and mode</p> * <p><b>Range of valid values:</b><br> * Coordinates must be between <code>[(0,0), (width, height))</code> of - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * depending on distortion correction capability and mode</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS = @@ -3099,9 +3159,17 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>The desired region of the sensor to read out for this capture.</p> * <p>This control can be used to implement digital zoom.</p> - * <p>The crop region coordinate system is based off - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the - * top-left corner of the sensor active array.</p> + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being + * the top-left pixel of the active array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the active array.</p> * <p>Output streams use this rectangle to produce their output, * cropping to a smaller region if necessary to maintain the * stream's aspect ratio, then scaling the sensor input to @@ -3120,20 +3188,30 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * outputs will crop horizontally (pillarbox), and 16:9 * streams will match exactly. These additional crops will * be centered within the crop region.</p> - * <p>The width and height of the crop region cannot - * be set to be smaller than + * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height + * of the crop region cannot be set to be smaller than * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p> + * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, the width + * and height of the crop region cannot be set to be smaller than + * <code>floor( preCorrectionActiveArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> + * and + * <code>floor( preCorrectionActiveArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, + * respectively.</p> * <p>The camera device may adjust the crop region to account * for rounding and other hardware requirements; the final * crop region used will be included in the output capture * result.</p> * <p><b>Units</b>: Pixel coordinates relative to - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p> + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction + * capability and mode</p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.graphics.Rect> SCALER_CROP_REGION = @@ -3624,12 +3702,23 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>List of landmarks for detected * faces.</p> - * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being + * the top-left pixel of the active array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with * <code>(0, 0)</code> being the top-left pixel of the active array.</p> * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL * This key is available on all devices.</p> * + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE * @hide */ @@ -3639,12 +3728,23 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>List of the bounding rectangles for detected * faces.</p> - * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with + * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being + * the top-left pixel of the active array.</p> + * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate + * system depends on the mode being set. + * When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with + * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array. + * When the distortion correction mode is not OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with * <code>(0, 0)</code> being the top-left pixel of the active array.</p> * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF * This key is available on all devices.</p> * + * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE * @hide */ @@ -4478,15 +4578,14 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * any correction at all would slow down capture rate. Every output stream will have a * similar amount of enhancement applied.</p> * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not - * applied to any RAW output. Metadata coordinates such as face rectangles or metering + * applied to any RAW output. Metadata coordinates such as face rectangles or metering * regions are also not affected by correction.</p> - * <p>Applications enabling distortion correction need to pay extra attention when converting - * image coordinates between corrected output buffers and the sensor array. For example, if - * the app supports tap-to-focus and enables correction, it then has to apply the distortion - * model described in {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} to the image buffer tap coordinates to properly - * calculate the tap position on the sensor active array to be used with - * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}. The same applies in reverse to detected face rectangles if - * they need to be drawn on top of the corrected output buffers.</p> + * <p>This control will be on by default on devices that support this control. Applications + * disabling distortion correction need to pay extra attention with the coordinate system of + * metering regions, crop region, and face rectangles. When distortion correction is OFF, + * metadata coordinates follow the coordinate system of + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata + * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> * <p><b>Possible values:</b> * <ul> * <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li> @@ -4497,9 +4596,10 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * - * @see CaptureRequest#CONTROL_AF_REGIONS * @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES * @see CameraCharacteristics#LENS_DISTORTION + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE * @see #DISTORTION_CORRECTION_MODE_OFF * @see #DISTORTION_CORRECTION_MODE_FAST * @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4347a30a793e..2439d23ced78 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7537,9 +7537,6 @@ public final class Settings { */ public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity"; - private static final Validator ASSIST_GESTURE_SENSITIVITY_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 1.0f); - /** * Whether the assist gesture should silence alerts. * @@ -7569,8 +7566,6 @@ public final class Settings { */ public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete"; - private static final Validator ASSIST_GESTURE_SETUP_COMPLETE_VALIDATOR = BOOLEAN_VALIDATOR; - /** * Control whether Night display is currently activated. * @hide @@ -8026,8 +8021,6 @@ public final class Settings { NFC_PAYMENT_DEFAULT_COMPONENT, AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, ASSIST_GESTURE_ENABLED, - ASSIST_GESTURE_SENSITIVITY, - ASSIST_GESTURE_SETUP_COMPLETE, ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, ASSIST_GESTURE_WAKE_ENABLED, VR_DISPLAY_MODE, @@ -8166,8 +8159,6 @@ public final class Settings { VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR); VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR); - VALIDATORS.put(ASSIST_GESTURE_SENSITIVITY, ASSIST_GESTURE_SENSITIVITY_VALIDATOR); - VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, ASSIST_GESTURE_SETUP_COMPLETE_VALIDATOR); VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR); VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR); diff --git a/core/java/android/service/autofill/TextValueSanitizer.java b/core/java/android/service/autofill/TextValueSanitizer.java index e5ad77a1e8d6..a8c080a17818 100644 --- a/core/java/android/service/autofill/TextValueSanitizer.java +++ b/core/java/android/service/autofill/TextValueSanitizer.java @@ -37,7 +37,7 @@ import java.util.regex.Pattern; * <p>For example, to remove spaces from groups of 4-digits in a credit card: * * <pre class="prettyprint"> - * new TextValueSanitizer(Pattern.compile("^(\\d{4})\\s?(\\d{4})\\s?(\\d{4})\\s?(\\d{4})$", + * new TextValueSanitizer(Pattern.compile("^(\\d{4})\\s?(\\d{4})\\s?(\\d{4})\\s?(\\d{4})$"), * "$1$2$3$4") * </pre> */ diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index 6df76fa2e09a..e6f948f2d969 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PermissionGroupInfo; @@ -590,7 +591,8 @@ public class AppSecurityPermissions { private void addPermToList(List<MyPermissionInfo> permList, MyPermissionInfo pInfo) { if (pInfo.mLabel == null) { - pInfo.mLabel = pInfo.loadLabel(mPm); + pInfo.mLabel = pInfo.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM + | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); } int idx = Collections.binarySearch(permList, pInfo, mPermComparator); if(localLOGV) Log.i(TAG, "idx="+idx+", list.size="+permList.size()); @@ -611,7 +613,9 @@ public class AppSecurityPermissions { } MyPermissionGroupInfo group = mPermGroups.get(pInfo.group); if (group != null) { - pInfo.mLabel = pInfo.loadLabel(mPm); + pInfo.mLabel = pInfo.loadSafeLabel(mPm, 20000, + PackageItemInfo.SAFE_LABEL_FLAG_TRIM + | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); addPermToList(group.mAllPermissions, pInfo); if (pInfo.mNew) { addPermToList(group.mNewPermissions, pInfo); @@ -622,14 +626,18 @@ public class AppSecurityPermissions { for (MyPermissionGroupInfo pgrp : mPermGroups.values()) { if (pgrp.labelRes != 0 || pgrp.nonLocalizedLabel != null) { - pgrp.mLabel = pgrp.loadLabel(mPm); + pgrp.mLabel = pgrp.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM + | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); } else { ApplicationInfo app; try { app = mPm.getApplicationInfo(pgrp.packageName, 0); - pgrp.mLabel = app.loadLabel(mPm); + pgrp.mLabel = app.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM + | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); } catch (NameNotFoundException e) { - pgrp.mLabel = pgrp.loadLabel(mPm); + pgrp.mLabel = pgrp.loadSafeLabel(mPm, 20000, + PackageItemInfo.SAFE_LABEL_FLAG_TRIM + | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); } } mPermGroupsList.add(pgrp); diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java index 26fb6b6415e4..07bb4533c4e0 100644 --- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java +++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java @@ -27,9 +27,11 @@ import android.text.TextUtils; public class AmbientDisplayConfiguration { private final Context mContext; + private final boolean mAlwaysOnByDefault; public AmbientDisplayConfiguration(Context context) { mContext = context; + mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled); } public boolean enabled(int user) { @@ -101,8 +103,8 @@ public class AmbientDisplayConfiguration { } public boolean alwaysOnEnabled(int user) { - return boolSettingDefaultOn(Settings.Secure.DOZE_ALWAYS_ON, user) && alwaysOnAvailable() - && !accessibilityInversionEnabled(user); + return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0) + && alwaysOnAvailable() && !accessibilityInversionEnabled(user); } public boolean alwaysOnAvailable() { diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java index 0fd610908fd5..4ba93bc50dff 100644 --- a/core/java/com/android/internal/widget/MessagingLayout.java +++ b/core/java/com/android/internal/widget/MessagingLayout.java @@ -60,6 +60,13 @@ import java.util.regex.Pattern; public class MessagingLayout extends FrameLayout { private static final float COLOR_SHIFT_AMOUNT = 60; + /** + * Pattren for filter some ingonable characters. + * p{Z} for any kind of whitespace or invisible separator. + * p{C} for any kind of punctuation character. + */ + private static final Pattern IGNORABLE_CHAR_PATTERN + = Pattern.compile("[\\p{C}\\p{Z}]"); private static final Pattern SPECIAL_CHAR_PATTERN = Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]"); private static final Consumer<MessagingMessage> REMOVE_MESSAGE @@ -233,7 +240,10 @@ public class MessagingLayout extends FrameLayout { continue; } if (!uniqueNames.containsKey(senderName)) { - char c = senderName.charAt(0); + // Only use visible characters to get uniqueNames + String pureSenderName = IGNORABLE_CHAR_PATTERN + .matcher(senderName).replaceAll("" /* replacement */); + char c = pureSenderName.charAt(0); if (uniqueCharacters.containsKey(c)) { // this character was already used, lets make it more unique. We first need to // resolve the existing character if it exists @@ -245,7 +255,7 @@ public class MessagingLayout extends FrameLayout { uniqueNames.put(senderName, findNameSplit((String) senderName)); } else { uniqueNames.put(senderName, Character.toString(c)); - uniqueCharacters.put(c, senderName); + uniqueCharacters.put(c, pureSenderName); } } } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0b5dd7e70e8b..6c01cfd2cae4 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -491,13 +491,21 @@ Note also: the order of this is important. The first upstream type for which a satisfying network exists is used. - --> + --> <integer-array translatable="false" name="config_tether_upstream_types"> <item>1</item> <item>7</item> <item>0</item> </integer-array> + <!-- When true, the tethering upstream network follows the current default + Internet network (except when the current default network is mobile, + in which case a DUN network will be used if required). + + When true, overrides the config_tether_upstream_types setting above. + --> + <bool translatable="false" name="config_tether_upstream_automatic">false</bool> + <!-- If the DUN connection for this CDMA device supports more than just DUN --> <!-- traffic you should list them here. --> <!-- If this device is not CDMA this is ignored. If this list is empty on --> @@ -659,9 +667,27 @@ <!-- Boolean indicating that wifi only link configuratios that have exact same credentials (i.e PSK) --> <bool translatable="false" name="config_wifi_only_link_same_credential_configurations">true</bool> - <!-- Boolean indicating whether framework needs to set the tx power limit for meeting SAR requirements - during voice calls --> - <bool translatable="false" name="config_wifi_framework_enable_voice_call_sar_tx_power_limit">false</bool> + <!-- Boolean indicating whether framework needs to set the tx power limit for meeting SAR requirements --> + <bool translatable="false" name="config_wifi_framework_enable_sar_tx_power_limit">false</bool> + + <!-- Boolean indicating whether framework needs to use body proximity to set the tx power limit + for meeting SAR requirements --> + <bool translatable="false" name="config_wifi_framework_enable_body_proximity_sar_tx_power_limit">false</bool> + + <!-- String for the sensor type for body/head proximity for SAR --> + <string translatable="false" name="config_wifi_sar_sensor_type"></string> + + <!-- Integer indicating event id by sar sensor for free space --> + <integer translatable="false" name="config_wifi_framework_sar_free_space_event_id">1</integer> + + <!-- Integer indicating event id by sar sensor for near hand --> + <integer translatable="false" name="config_wifi_framework_sar_near_hand_event_id">2</integer> + + <!-- Integer indicating event id by sar sensor for near head --> + <integer translatable="false" name="config_wifi_framework_sar_near_head_event_id">3</integer> + + <!-- Integer indicating event id by sar sensor for near body --> + <integer translatable="false" name="config_wifi_framework_sar_near_body_event_id">4</integer> <!-- Wifi driver supports batched scan --> <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool> @@ -2085,6 +2111,10 @@ states. --> <bool name="config_dozeAlwaysOnDisplayAvailable">false</bool> + <!-- Control whether the always on display mode is enabled by default. This value will be used + during initialization when the setting is still null. --> + <bool name="config_dozeAlwaysOnEnabled">true</bool> + <!-- Whether the display blanks itself when transitioning from a doze to a non-doze state --> <bool name="config_displayBlanksAfterDoze">false</bool> @@ -3447,4 +3477,6 @@ <!-- Whether or not swipe up gesture's opt-in setting is available on this device --> <bool name="config_swipe_up_gesture_setting_available">false</bool> + <!-- Whether or not we should show the option to show battery percentage --> + <bool name="config_battery_percentage_setting_available">true</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f80abc1a04f9..b90034e2fd69 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -336,7 +336,13 @@ <java-symbol type="bool" name="config_wifi_framework_enable_associated_network_selection" /> <java-symbol type="bool" name="config_wifi_framework_use_single_radio_chain_scan_results_network_selection" /> <java-symbol type="bool" name="config_wifi_only_link_same_credential_configurations" /> - <java-symbol type="bool" name="config_wifi_framework_enable_voice_call_sar_tx_power_limit" /> + <java-symbol type="bool" name="config_wifi_framework_enable_sar_tx_power_limit" /> + <java-symbol type="bool" name="config_wifi_framework_enable_body_proximity_sar_tx_power_limit" /> + <java-symbol type="string" name="config_wifi_sar_sensor_type" /> + <java-symbol type="integer" name="config_wifi_framework_sar_free_space_event_id" /> + <java-symbol type="integer" name="config_wifi_framework_sar_near_hand_event_id" /> + <java-symbol type="integer" name="config_wifi_framework_sar_near_head_event_id" /> + <java-symbol type="integer" name="config_wifi_framework_sar_near_body_event_id" /> <java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" /> <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" /> <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" /> @@ -1822,6 +1828,7 @@ <java-symbol type="array" name="config_tether_bluetooth_regexs" /> <java-symbol type="array" name="config_tether_dhcp_range" /> <java-symbol type="array" name="config_tether_upstream_types" /> + <java-symbol type="bool" name="config_tether_upstream_automatic" /> <java-symbol type="array" name="config_tether_apndata" /> <java-symbol type="array" name="config_tether_usb_regexs" /> <java-symbol type="array" name="config_tether_wifi_regexs" /> @@ -2193,6 +2200,7 @@ <java-symbol type="string" name="ext_media_move_failure_message" /> <java-symbol type="style" name="Animation.RecentApplications" /> <java-symbol type="integer" name="dock_enter_exit_duration" /> + <java-symbol type="bool" name="config_battery_percentage_setting_available" /> <!-- ImfTest --> <java-symbol type="layout" name="auto_complete_list" /> @@ -3231,6 +3239,7 @@ <java-symbol type="dimen" name="config_inCallNotificationVolume" /> <java-symbol type="string" name="config_inCallNotificationSound" /> <java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" /> + <java-symbol type="bool" name="config_dozeAlwaysOnEnabled" /> <java-symbol type="bool" name="config_displayBlanksAfterDoze" /> <java-symbol type="bool" name="config_displayBrightnessBucketsInDoze" /> <java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index dea32358824b..e50efa970f3b 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -508,6 +508,8 @@ public class SettingsBackupTest { Settings.Secure.ANR_SHOW_BACKGROUND, Settings.Secure.ASSISTANT, Settings.Secure.ASSIST_DISCLOSURE_ENABLED, + Settings.Secure.ASSIST_GESTURE_SENSITIVITY, + Settings.Secure.ASSIST_GESTURE_SETUP_COMPLETE, Settings.Secure.ASSIST_SCREENSHOT_ENABLED, Settings.Secure.ASSIST_STRUCTURE_ENABLED, Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 54358e355444..e397ed90c2e2 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -57,6 +57,8 @@ import android.view.View; import com.android.internal.R; import com.android.internal.util.VirtualRefBasePtr; +import dalvik.annotation.optimization.FastNative; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -64,7 +66,6 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; -import dalvik.annotation.optimization.FastNative; /** * This class animates properties of a {@link android.graphics.drawable.VectorDrawable} with @@ -167,7 +168,7 @@ import dalvik.annotation.optimization.FastNative; * </p> * Below is an example of a VectorDrawable defined in vectordrawable.xml. This VectorDrawable is * referred to by its file name (not including file suffix) in the - * <a href="AVDExample">AnimatedVectorDrawable XML example</a>. + * <a href="#AVDExample">AnimatedVectorDrawable XML example</a>. * <pre> * <vector xmlns:android="http://schemas.android.com/apk/res/android" * android:height="64dp" diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java index aae1f517eeaf..6bf52bdb60d3 100644 --- a/media/java/android/media/MediaHTTPConnection.java +++ b/media/java/android/media/MediaHTTPConnection.java @@ -323,8 +323,10 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { StrictMode.setThreadPolicy(policy); try { - if (offset != mCurrentOffset) { - seekTo(offset); + synchronized(this) { + if (offset != mCurrentOffset) { + seekTo(offset); + } } int n = mInputStream.read(data, 0, size); @@ -366,7 +368,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } @Override - public long getSize() { + public synchronized long getSize() { if (mConnection == null) { try { seekTo(0); @@ -379,7 +381,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } @Override - public String getMIMEType() { + public synchronized String getMIMEType() { if (mConnection == null) { try { seekTo(0); diff --git a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml index 9c24c2ce9f83..47e1059fab44 100644 --- a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml +++ b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml @@ -22,5 +22,5 @@ android:viewportHeight="24.0"> <path android:fillColor="#FFFFFFFF" - android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/> + android:pathData="M7.4,10.94H2.45V5.99l2,0.01v1.53l4.61,-4.61c0.64,-0.64 1.67,-0.66 2.29,-0.04l8.18,8.18h-2.83l-6.48,-6.48L5.86,8.95H7.4V10.94zM16.6,13.06l0.01,2h1.53l-4.36,4.36l-6.48,-6.48H4.46l8.19,8.19c0.62,0.62 1.65,0.6 2.29,-0.04l4.61,-4.61l0.01,0.01v1.53h1.99v-4.95H16.6z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml index 2cd788303279..3304c19b1ed8 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml @@ -17,16 +17,16 @@ <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> <aapt:attr name="android:drawable"> <vector android:name="root" - android:width="21dp" - android:height="21dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:width="28dp" + android:height="28dp" + android:viewportWidth="28.0" + android:viewportHeight="28.0"> <!-- Use scaleX to flip icon so arrows always point in the direction of motion --> - <group android:name="icon" android:pivotX="12" android:pivotY="12" + <group android:name="icon" android:pivotX="14" android:pivotY="14" android:scaleX="?attr/rotateButtonScaleX"> <!-- Tint color to be set directly --> <path android:fillColor="#FFFFFFFF" - android:pathData="M19,12c0,1.72 -0.63,3.3 -1.66,4.52l-1.44,-1.44C16.58,14.23 17,13.17 17,12c0,-2.76 -2.24,-5 -5,-5c-0.06,0 -0.11,0.01 -0.17,0.01l1.08,1.08L11.5,9.5L8,6l3.5,-3.5l1.41,1.42l-1.09,1.09C11.88,5.01 11.94,5 12,5C15.87,5 19,8.13 19,12zM12.5,14.51l-1.41,1.41l1.06,1.06C12.1,16.99 12.05,17 12,17c-2.76,0 -5,-2.24 -5,-5c0,-1.17 0.42,-2.23 1.09,-3.08L6.66,7.48C5.62,8.7 5,10.28 5,12c0,3.87 3.13,7 7,7c0.06,0 0.13,-0.01 0.19,-0.01v0l-1.1,1.1l1.41,1.41L16,18L12.5,14.51z"/> + android:pathData="M12.02,10.83L9.25,8.06l2.77,-2.77l1.12,1.12l-0.85,0.86h5.16c0.72,0 1.31,0.56 1.31,1.26v9.16l-1.58,-1.58V8.85h-4.89l0.86,0.86L12.02,10.83zM15.98,17.17l-1.12,1.12l0.85,0.86h-4.88v-7.26L9.25,10.3v9.17c0,0.7 0.59,1.26 1.31,1.26h5.16v0.01l-0.85,0.85l1.12,1.12l2.77,-2.77L15.98,17.17z"/> </group> </vector> </aapt:attr> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f00957a14e09..3b58b7249b05 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1012,4 +1012,7 @@ <!-- How much into a DisplayCutout's bounds we can go, on each side --> <dimen name="display_cutout_margin_consumption">0px</dimen> + <!-- How much we expand the touchable region of the status bar below the notch to catch touches + that just start below the notch. --> + <dimen name="display_cutout_touchable_region_size">12dp</dimen> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java index 5b0f1c39f74b..66475e29128d 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java @@ -334,8 +334,10 @@ public class CarrierText extends TextView { break; case SimPermDisabled: - carrierText = getContext().getText( - R.string.keyguard_permanent_disabled_sim_message_short); + carrierText = makeCarrierStringOnEmergencyCapable( + getContext().getText( + R.string.keyguard_permanent_disabled_sim_message_short), + text); break; case SimMissingLocked: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 41df196c62b0..225f7fcc9de9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -73,6 +73,7 @@ public class KeyguardStatusView extends GridLayout implements private ArraySet<View> mVisibleInDoze; private boolean mPulsing; + private boolean mWasPulsing; private float mDarkAmount = 0; private int mTextColor; private float mWidgetPadding; @@ -224,7 +225,8 @@ public class KeyguardStatusView extends GridLayout implements boolean hasHeader = mKeyguardSlice.hasHeader(); boolean smallClock = hasHeader || mPulsing; long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION; - long delay = smallClock ? 0 : duration / 4; + long delay = smallClock || mWasPulsing ? 0 : duration / 4; + mWasPulsing = false; boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null && mKeyguardSlice.getLayoutTransition().isRunning(); @@ -448,6 +450,12 @@ public class KeyguardStatusView extends GridLayout implements } public void setPulsing(boolean pulsing, boolean animate) { + if (mPulsing == pulsing) { + return; + } + if (mPulsing) { + mWasPulsing = true; + } mPulsing = pulsing; mKeyguardSlice.setPulsing(pulsing, animate); updateDozeVisibleViews(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 62cd13b7dc17..ef3aa42727e9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1589,6 +1589,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + public boolean isKeyguardVisible() { + return mKeyguardIsVisible; + } + /** * Notifies that the visibility state of Keyguard has changed. * diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 59501f0970c2..81dd5eb7fed8 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -55,6 +55,7 @@ import com.android.systemui.statusbar.policy.IconLogger; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.Utils.DisableStateTracker; +import com.android.systemui.R; import java.text.NumberFormat; @@ -72,6 +73,7 @@ public class BatteryMeterView extends LinearLayout implements private int mTextColor; private int mLevel; private boolean mForceShowPercent; + private boolean mShowPercentAvailable; private int mDarkModeBackgroundColor; private int mDarkModeFillColor; @@ -111,6 +113,9 @@ public class BatteryMeterView extends LinearLayout implements atts.recycle(); mSettingObserver = new SettingObserver(new Handler(context.getMainLooper())); + mShowPercentAvailable = context.getResources().getBoolean( + com.android.internal.R.bool.config_battery_percentage_setting_available); + addOnAttachStateChangeListener( new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS)); @@ -259,8 +264,11 @@ public class BatteryMeterView extends LinearLayout implements private void updateShowPercent() { final boolean showing = mBatteryPercentView != null; - if (0 != Settings.System.getIntForUser(getContext().getContentResolver(), - SHOW_BATTERY_PERCENT, 0, mUser) || mForceShowPercent) { + final boolean systemSetting = 0 != Settings.System + .getIntForUser(getContext().getContentResolver(), + SHOW_BATTERY_PERCENT, 0, mUser); + + if ((mShowPercentAvailable && systemSetting) || mForceShowPercent) { if (!showing) { mBatteryPercentView = loadPercentView(); if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index efaf557660d2..194679cc626e 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -52,6 +52,7 @@ import android.view.View; import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.ViewTreeObserver; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; @@ -89,6 +90,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { private float mDensity; private WindowManager mWindowManager; private int mRotation; + private DisplayCutoutView mCutoutTop; + private DisplayCutoutView mCutoutBottom; + private boolean mPendingRotationChange; @Override public void start() { @@ -122,6 +126,22 @@ public class ScreenDecorations extends SystemUI implements Tunable { @Override public void onDisplayChanged(int displayId) { + if (mOverlay != null && mBottomOverlay != null + && mRotation != RotationUtils.getExactRotation(mContext)) { + // We cannot immediately update the orientation. Otherwise + // WindowManager is still deferring layout until it has finished dispatching + // the config changes, which may cause divergence between what we draw + // (new orientation), and where we are placed on the screen (old orientation). + // Instead we wait until either: + // - we are trying to redraw. This because WM resized our window and told us to. + // - the config change has been dispatched, so WM is no longer deferring layout. + mPendingRotationChange = true; + mOverlay.getViewTreeObserver().addOnPreDrawListener( + new RestartingPreDrawListener(mOverlay)); + mBottomOverlay.getViewTreeObserver().addOnPreDrawListener( + new RestartingPreDrawListener(mBottomOverlay)); + + } updateOrientation(); } }; @@ -135,14 +155,14 @@ public class ScreenDecorations extends SystemUI implements Tunable { private void setupDecorations() { mOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); - DisplayCutoutView cutoutTop = new DisplayCutoutView(mContext, true, - this::updateWindowVisibilities); - ((ViewGroup)mOverlay).addView(cutoutTop); + mCutoutTop = new DisplayCutoutView(mContext, true, + this::updateWindowVisibilities, this); + ((ViewGroup)mOverlay).addView(mCutoutTop); mBottomOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); - DisplayCutoutView cutoutBottom = new DisplayCutoutView(mContext, false, - this::updateWindowVisibilities); - ((ViewGroup)mBottomOverlay).addView(cutoutBottom); + mCutoutBottom = new DisplayCutoutView(mContext, false, + this::updateWindowVisibilities, this); + ((ViewGroup)mBottomOverlay).addView(mCutoutBottom); mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); mOverlay.setAlpha(0); @@ -172,8 +192,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { ((ImageView) mOverlay.findViewById(R.id.right)).setImageTintList(tintList); ((ImageView) mBottomOverlay.findViewById(R.id.left)).setImageTintList(tintList); ((ImageView) mBottomOverlay.findViewById(R.id.right)).setImageTintList(tintList); - cutoutTop.setColor(tint); - cutoutBottom.setColor(tint); + mCutoutTop.setColor(tint); + mCutoutBottom.setColor(tint); } }; setting.setListening(true); @@ -199,6 +219,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { @Override protected void onConfigurationChanged(Configuration newConfig) { + mPendingRotationChange = false; updateOrientation(); if (shouldDrawCutout() && mOverlay == null) { setupDecorations(); @@ -206,6 +227,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { } protected void updateOrientation() { + if (mPendingRotationChange) { + return; + } int newRotation = RotationUtils.getExactRotation(mContext); if (newRotation != mRotation) { mRotation = newRotation; @@ -245,6 +269,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { updateView(bottomRight, Gravity.TOP | Gravity.LEFT, 0); } + mCutoutTop.setRotation(mRotation); + mCutoutBottom.setRotation(mRotation); + updateWindowVisibilities(); } @@ -416,15 +443,19 @@ public class ScreenDecorations extends SystemUI implements Tunable { private final Rect mBoundingRect = new Rect(); private final Path mBoundingPath = new Path(); private final int[] mLocation = new int[2]; - private final boolean mStart; + private final boolean mInitialStart; private final Runnable mVisibilityChangedListener; + private final ScreenDecorations mDecorations; private int mColor = Color.BLACK; + private boolean mStart; + private int mRotation; public DisplayCutoutView(Context context, boolean start, - Runnable visibilityChangedListener) { + Runnable visibilityChangedListener, ScreenDecorations decorations) { super(context); - mStart = start; + mInitialStart = start; mVisibilityChangedListener = visibilityChangedListener; + mDecorations = decorations; setId(R.id.display_cutout); } @@ -475,7 +506,22 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + public void setRotation(int rotation) { + mRotation = rotation; + update(); + } + + private boolean isStart() { + final boolean flipped = (mRotation == RotationUtils.ROTATION_SEASCAPE + || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN); + return flipped ? !mInitialStart : mInitialStart; + } + private void update() { + if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) { + return; + } + mStart = isStart(); requestLayout(); getDisplay().getDisplayInfo(mInfo); mBounds.setEmpty(); @@ -560,31 +606,34 @@ public class ScreenDecorations extends SystemUI implements Tunable { resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0)); } - public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, Rect out) { + public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, + Rect out) { + Region bounds = boundsFromDirection(displayCutout, gravity); + out.set(bounds.getBounds()); + bounds.recycle(); + } + + public static Region boundsFromDirection(DisplayCutout displayCutout, int gravity) { Region bounds = displayCutout.getBounds(); switch (gravity) { case Gravity.TOP: bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; case Gravity.LEFT: bounds.op(0, 0, displayCutout.getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; case Gravity.BOTTOM: bounds.op(0, displayCutout.getSafeInsetTop() + 1, Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; case Gravity.RIGHT: bounds.op(displayCutout.getSafeInsetLeft() + 1, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; } - bounds.recycle(); + return bounds; } private void localBounds(Rect out) { @@ -635,4 +684,28 @@ public class ScreenDecorations extends SystemUI implements Tunable { return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation == RotationUtils.ROTATION_SEASCAPE; } + + /** + * A pre-draw listener, that cancels the draw and restarts the traversal with the updated + * window attributes. + */ + private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener { + + private final View mView; + + private RestartingPreDrawListener(View view) { + mView = view; + } + + @Override + public boolean onPreDraw() { + mPendingRotationChange = false; + mView.getViewTreeObserver().removeOnPreDrawListener(this); + // This changes the window attributes - we need to restart the traversal for them to + // take effect. + updateOrientation(); + mView.invalidate(); + return false; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java index 9a43d9e07610..3c8a461d3f73 100644 --- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java +++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java @@ -21,7 +21,6 @@ import android.app.WallpaperManager; import android.content.Context; import android.os.Handler; import android.os.RemoteException; -import android.os.Trace; import android.os.UserHandle; import android.util.Log; import android.view.Display; @@ -46,7 +45,7 @@ import java.util.Arrays; public class SysuiColorExtractor extends ColorExtractor implements Dumpable { private static final String TAG = "SysuiColorExtractor"; private boolean mWallpaperVisible; - private boolean mMediaBackdropVisible; + private boolean mHasBackdrop; // Colors to return when the wallpaper isn't visible private final GradientColors mWpHiddenColors; @@ -165,7 +164,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable { return mWpHiddenColors; } } else { - if (mMediaBackdropVisible) { + if (mHasBackdrop) { return mWpHiddenColors; } else { return super.getColors(which, type); @@ -181,9 +180,9 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable { } } - public void setMediaBackdropVisible(boolean visible) { - if (mMediaBackdropVisible != visible) { - mMediaBackdropVisible = visible; + public void setHasBackdrop(boolean hasBackdrop) { + if (mHasBackdrop != hasBackdrop) { + mHasBackdrop = hasBackdrop; triggerColorsChanged(WallpaperManager.FLAG_LOCK); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index 8d8e20669a1f..ce9d7e160e0e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -479,7 +479,7 @@ public class RecentsOnboarding { ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, x, -mNavBarHeight / 2, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, flags, PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java index 39485c3c8800..29e0edaf25cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java @@ -178,11 +178,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { * @param translationX how to translate the horizontal position */ public void setPanelTranslation(float translationX) { - if (isLayoutRtl()) { - setTranslationX(translationX + mCutOutInset); - } else { - setTranslationX(translationX - mCutOutInset); - } + setTranslationX(translationX); updateDrawingRect(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index fac77689e289..306319903ecb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -482,8 +482,8 @@ public class NotificationShelf extends ActivatableNotificationView implements iconTransformDistance = Math.min(iconTransformDistance, fullHeight); if (isLastChild) { fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight()); - iconTransformDistance = Math.min(iconTransformDistance, - row.getMinHeight() - getIntrinsicHeight() * icon.getIconScale()); + iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight() + - getIntrinsicHeight()); } float viewEnd = viewStart + fullHeight; if (expandingAnimated && mAmbientState.getScrollY() == 0 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 27cb077394b1..c0e7ac4810d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -197,6 +197,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi mDarkAmount); final int outerBounds = mStatusBarIconSize; mIconScale = (float)imageBounds / (float)outerBounds; + updatePivot(); } private void updateIconScaleForSystemIcons() { @@ -859,6 +860,12 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi mLayoutRunnable.run(); mLayoutRunnable = null; } + updatePivot(); + } + + private void updatePivot() { + setPivotX((1 - mIconScale) / 2.0f * getWidth()); + setPivotY((getHeight() - mIconScale * getWidth()) / 2.0f); } public void executeOnLayout(Runnable runnable) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 409a78391975..4e7f4f38ebd3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import android.graphics.Point; import android.graphics.Rect; +import android.view.DisplayCutout; import android.view.View; import android.view.WindowInsets; @@ -159,8 +160,15 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } WindowInsets windowInset = mStackScroller.getRootWindowInsets(); - return windowInset.getSystemWindowInsetLeft() + mStackScroller.getRight() - + windowInset.getSystemWindowInsetRight() - realDisplaySize; + DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null; + int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0; + int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0; + int cutoutLeft = (cutout != null) ? cutout.getSafeInsetLeft() : 0; + int cutoutRight = (cutout != null) ? cutout.getSafeInsetRight() : 0; + int leftInset = Math.max(sysWinLeft, cutoutLeft); + int rightInset = Math.max(sysWinRight, cutoutRight); + + return leftInset + mStackScroller.getRight() + rightInset - realDisplaySize; } public void updatePanelTranslation() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index fa0a774c249e..0aad4389ceec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -21,15 +21,22 @@ import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.Region.Op; import android.support.v4.util.ArraySet; import android.util.Log; import android.util.Pools; +import android.view.DisplayCutout; +import android.view.Gravity; import android.view.View; import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.InternalInsetsInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.ScreenDecorations; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.StatusBarState; @@ -41,6 +48,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashSet; +import java.util.List; import java.util.Stack; /** @@ -60,6 +68,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private int mStatusBarHeight; private int mHeadsUpInset; + private int mDisplayCutoutTouchableRegionSize; private boolean mTrackingHeadsUp; private HashSet<String> mSwipedOutKeys = new HashSet<>(); private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>(); @@ -120,6 +129,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, com.android.internal.R.dimen.status_bar_height); mHeadsUpInset = mStatusBarHeight + resources.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); + mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize( + R.dimen.display_cutout_touchable_region_size); } @Override @@ -128,6 +139,11 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, initResources(); } + @Override + public void onOverlayChanged() { + initResources(); + } + /////////////////////////////////////////////////////////////////////////////////////////////// // Public methods: @@ -301,12 +317,32 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height); - } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) { - info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); - info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight); + } else { + setCollapsedTouchableInsets(info); } } + private void setCollapsedTouchableInsets(ViewTreeObserver.InternalInsetsInfo info) { + info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); + info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight); + updateRegionForNotch(info.touchableRegion); + } + + private void updateRegionForNotch(Region region) { + DisplayCutout cutout = mStatusBarWindowView.getRootWindowInsets().getDisplayCutout(); + if (cutout == null) { + return; + } + + // Expand touchable region such that we also catch touches that just start below the notch + // area. + Region bounds = ScreenDecorations.DisplayCutoutView.boundsFromDirection( + cutout, Gravity.TOP); + bounds.translate(0, mDisplayCutoutTouchableRegionSize); + region.op(bounds, Op.UNION); + bounds.recycle(); + } + @Override public void onConfigChanged(Configuration newConfig) { Resources resources = mContext.getResources(); @@ -403,7 +439,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private void updateTouchableRegionListener() { boolean shouldObserve = hasPinnedHeadsUp() || mHeadsUpGoingAway - || mWaitingOnCollapseWhenGoingAway; + || mWaitingOnCollapseWhenGoingAway + || mStatusBarWindowView.getRootWindowInsets().getDisplayCutout() != null; if (shouldObserve == mIsObserving) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 0bd3cc795bc3..db84222ec5a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -67,6 +67,7 @@ public class KeyguardStatusBarView extends RelativeLayout private static final int LAYOUT_CUTOUT = 1; private static final int LAYOUT_NO_CUTOUT = 2; + private boolean mShowPercentAvailable; private boolean mBatteryCharging; private boolean mKeyguardUserSwitcherShowing; private boolean mBatteryListening; @@ -165,6 +166,8 @@ public class KeyguardStatusBarView extends RelativeLayout R.dimen.system_icons_super_container_avatarless_margin_end); mCutoutSideNudge = getResources().getDimensionPixelSize( R.dimen.display_cutout_margin_consumption); + mShowPercentAvailable = getContext().getResources().getBoolean( + com.android.internal.R.bool.config_battery_percentage_setting_available); } private void updateVisibilities() { @@ -186,7 +189,7 @@ public class KeyguardStatusBarView extends RelativeLayout mMultiUserSwitch.setVisibility(View.GONE); } } - mBatteryView.setForceShowPercent(mBatteryCharging); + mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable); } private void updateSystemIconsLayoutParams() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 44d666eb0d65..2bfdfebae82d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -47,6 +47,8 @@ public class NotificationIconAreaController implements DarkReceiver { private final Rect mTintArea = new Rect(); private NotificationStackScrollLayout mNotificationScrollLayout; private Context mContext; + private boolean mFullyDark; + private boolean mHasShelfIconsWhenFullyDark; public NotificationIconAreaController(Context context, StatusBar statusBar) { mStatusBar = statusBar; @@ -173,13 +175,40 @@ public class NotificationIconAreaController implements DarkReceiver { public void updateNotificationIcons() { updateStatusBarIcons(); - updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons, - NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */, - false /* hideRepliedMessages */); + updateShelfIcons(); + updateHasShelfIconsWhenFullyDark(); applyNotificationIconsTint(); } + private void updateHasShelfIconsWhenFullyDark() { + boolean hasIconsWhenFullyDark = false; + for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) { + View view = mNotificationScrollLayout.getChildAt(i); + if (view instanceof ExpandableNotificationRow) { + NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry(); + if (shouldShowNotificationIcon(ent, + NotificationShelf.SHOW_AMBIENT_ICONS /* showAmbient */, + false /* hideDismissed */, + true /* hideReplied */)) { + hasIconsWhenFullyDark = true; + break; + } + } + } + mHasShelfIconsWhenFullyDark = hasIconsWhenFullyDark; + } + + public boolean hasShelfIconsWhenFullyDark() { + return mHasShelfIconsWhenFullyDark; + } + + private void updateShelfIcons() { + updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons, + NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */, + mFullyDark /* hideRepliedMessages */); + } + public void updateStatusBarIcons() { updateIconsForLayout(entry -> entry.icon, mNotificationIcons, false /* showAmbient */, true /* hideDismissed */, true /* hideRepliedMessages */); @@ -320,6 +349,11 @@ public class NotificationIconAreaController implements DarkReceiver { v.setDecorColor(mIconTint); } + public void setFullyDark(boolean fullyDark) { + mFullyDark = fullyDark; + updateShelfIcons(); + } + public void setDark(boolean dark) { mNotificationIcons.setDark(dark, false, 0); mShelfIcons.setDark(dark, false, 0); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 2f18aad9612d..2d8b54527cb9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -2489,7 +2489,7 @@ public class NotificationPanelView extends PanelView implements } protected void setVerticalPanelTranslation(float translation) { - mNotificationStackScroller.setTranslationX(translation); + mNotificationStackScroller.setVerticalPanelTranslation(translation); mQsFrame.setTranslationX(translation); int size = mVerticalTranslationListener.size(); for (int i = 0; i < size; i++) { @@ -2736,13 +2736,14 @@ public class NotificationPanelView extends PanelView implements public void setPulsing(boolean pulsing) { mPulsing = pulsing; - final boolean canAnimatePulse = - !DozeParameters.getInstance(mContext).getDisplayNeedsBlanking(); - if (canAnimatePulse) { + DozeParameters dozeParameters = DozeParameters.getInstance(mContext); + final boolean animatePulse = !dozeParameters.getDisplayNeedsBlanking() + && dozeParameters.getAlwaysOn(); + if (animatePulse) { mAnimateNextPositionUpdate = true; } - mNotificationStackScroller.setPulsing(pulsing, canAnimatePulse); - mKeyguardStatusView.setPulsing(pulsing, canAnimatePulse); + mNotificationStackScroller.setPulsing(pulsing, animatePulse); + mKeyguardStatusView.setPulsing(pulsing, animatePulse); } public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 5477f882e5f9..075883a8ac52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -331,30 +331,25 @@ public class PhoneStatusBarView extends PanelBar { // or letterboxing from the right or left sides. FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - if (mDisplayCutout == null) { + if (mDisplayCutout == null || mDisplayCutout.isEmpty() + || mLastOrientation != ORIENTATION_PORTRAIT || cornerCutoutMargins == null) { lp.leftMargin = 0; lp.rightMargin = 0; return; } - lp.leftMargin = mDisplayCutout.getSafeInsetLeft(); - lp.rightMargin = mDisplayCutout.getSafeInsetRight(); - - if (cornerCutoutMargins != null) { - lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first); - lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second); - - // If we're already inset enough (e.g. on the status bar side), we can have 0 margin - WindowInsets insets = getRootWindowInsets(); - int leftInset = insets.getSystemWindowInsetLeft(); - int rightInset = insets.getSystemWindowInsetRight(); - if (lp.leftMargin <= leftInset) { - lp.leftMargin = 0; - } - if (lp.rightMargin <= rightInset) { - lp.rightMargin = 0; - } + lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first); + lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second); + // If we're already inset enough (e.g. on the status bar side), we can have 0 margin + WindowInsets insets = getRootWindowInsets(); + int leftInset = insets.getSystemWindowInsetLeft(); + int rightInset = insets.getSystemWindowInsetRight(); + if (lp.leftMargin <= leftInset) { + lp.leftMargin = 0; + } + if (lp.rightMargin <= rightInset) { + lp.rightMargin = 0; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 279ede914fa7..482cffa05901 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -29,9 +29,7 @@ import android.os.Handler; import android.os.Trace; import android.util.Log; import android.util.MathUtils; -import android.view.Choreographer; import android.view.View; -import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -43,12 +41,11 @@ import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListen import com.android.internal.graphics.ColorUtils; import com.android.internal.util.function.TriConsumer; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.statusbar.ExpandableNotificationRow; -import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.stack.ViewState; import com.android.systemui.util.AlarmTimeout; @@ -482,21 +479,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // Make sure we have the right gradients and their opacities will satisfy GAR. if (mNeedsDrawableColorUpdate) { mNeedsDrawableColorUpdate = false; - final GradientColors currentScrimColors; - if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_SCRIMMED - || mState == ScrimState.BOUNCER) { - // Always animate color changes if we're seeing the keyguard - mScrimInFront.setColors(mLockColors, true /* animated */); - mScrimBehind.setColors(mLockColors, true /* animated */); - currentScrimColors = mLockColors; - } else { - // Only animate scrim color if the scrim view is actually visible - boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0; - boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0; - mScrimInFront.setColors(mSystemColors, animateScrimInFront); - mScrimBehind.setColors(mSystemColors, animateScrimBehind); - currentScrimColors = mSystemColors; - } + boolean isKeyguard = mKeyguardUpdateMonitor.isKeyguardVisible() && !mKeyguardOccluded; + GradientColors currentScrimColors = isKeyguard ? mLockColors : mSystemColors; + // Only animate scrim color if the scrim view is actually visible + boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen; + boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen; + mScrimInFront.setColors(currentScrimColors, animateScrimInFront); + mScrimBehind.setColors(currentScrimColors, animateScrimBehind); // Calculate minimum scrim opacity for white or black text. int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE; @@ -899,6 +888,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo updateScrims(); } + public void setHasBackdrop(boolean hasBackdrop) { + ScrimState[] states = ScrimState.values(); + for (int i = 0; i < states.length; i++) { + states[i].setHasBackdrop(hasBackdrop); + } + } + public interface Callback { default void onStart() { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 713356bc2381..ec6ada409fcc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -20,7 +20,6 @@ import android.graphics.Color; import android.os.Trace; import android.util.MathUtils; -import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.stack.StackStateAnimator; @@ -106,8 +105,7 @@ public enum ScrimState { public void prepare(ScrimState previousState) { final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn(); mBlankScreen = mDisplayRequiresBlanking; - mCurrentBehindAlpha = mWallpaperSupportsAmbientMode - && !mKeyguardUpdateMonitor.hasLockscreenWallpaper() ? 0f : 1f; + mCurrentBehindAlpha = mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f; mCurrentInFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f; mCurrentInFrontTint = Color.BLACK; mCurrentBehindTint = Color.BLACK; @@ -131,8 +129,7 @@ public enum ScrimState { public void prepare(ScrimState previousState) { mCurrentInFrontAlpha = 0; mCurrentInFrontTint = Color.BLACK; - mCurrentBehindAlpha = mWallpaperSupportsAmbientMode - && !mKeyguardUpdateMonitor.hasLockscreenWallpaper() ? 0f : 1f; + mCurrentBehindAlpha = mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f; mCurrentBehindTint = Color.BLACK; mBlankScreen = mDisplayRequiresBlanking; } @@ -178,8 +175,8 @@ public enum ScrimState { DozeParameters mDozeParameters; boolean mDisplayRequiresBlanking; boolean mWallpaperSupportsAmbientMode; - KeyguardUpdateMonitor mKeyguardUpdateMonitor; int mIndex; + boolean mHasBackdrop; ScrimState(int index) { mIndex = index; @@ -190,7 +187,6 @@ public enum ScrimState { mScrimBehind = scrimBehind; mDozeParameters = dozeParameters; mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking(); - mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(scrimInFront.getContext()); } public void prepare(ScrimState previousState) { @@ -256,4 +252,8 @@ public enum ScrimState { public boolean isLowPowerState() { return false; } + + public void setHasBackdrop(boolean hasBackdrop) { + mHasBackdrop = hasBackdrop; + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 7bbeed63fd98..07b0e1d242d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -607,6 +607,12 @@ public class StatusBar extends SystemUI implements DemoMode, maybeEscalateHeadsUp(); } } + + @Override + public void onStrongAuthStateChanged(int userId) { + super.onStrongAuthStateChanged(userId); + mEntryManager.updateNotifications(); + } }; private NavigationBarFragment mNavigationBar; @@ -823,6 +829,7 @@ public class StatusBar extends SystemUI implements DemoMode, .createNotificationIconAreaController(context, this); inflateShelf(); mNotificationIconAreaController.setupShelf(mNotificationShelf); + mStackScroller.setIconAreaController(mNotificationIconAreaController); Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController); FragmentHostManager.get(mStatusBarWindow) .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { @@ -840,6 +847,7 @@ public class StatusBar extends SystemUI implements DemoMode, } mHeadsUpAppearanceController = new HeadsUpAppearanceController( mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow); + mStatusBarWindow.setStatusBarView(mStatusBarView); setAreThereNotifications(); checkBarModes(); }).getFragmentManager() @@ -1645,8 +1653,12 @@ public class StatusBar extends SystemUI implements DemoMode, && mStatusBarKeyguardViewManager.isOccluded(); final boolean hasArtwork = artworkDrawable != null; + mColorExtractor.setHasBackdrop(hasArtwork); + if (mScrimController != null) { + mScrimController.setHasBackdrop(hasArtwork); + } - if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && !mDozing + if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && (mState != StatusBarState.SHADE || allowWhenShade) && mFingerprintUnlockController.getMode() != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING @@ -1662,7 +1674,6 @@ public class StatusBar extends SystemUI implements DemoMode, mBackdrop.setAlpha(1f); } mStatusBarWindowManager.setBackdropShowing(true); - mColorExtractor.setMediaBackdropVisible(true); metaDataChanged = true; if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); @@ -1714,7 +1725,6 @@ public class StatusBar extends SystemUI implements DemoMode, if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); } - mColorExtractor.setMediaBackdropVisible(false); boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange(); if (mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING @@ -3846,7 +3856,7 @@ public class StatusBar extends SystemUI implements DemoMode, * Switches theme from light to dark and vice-versa. */ protected void updateTheme() { - final boolean inflated = mStackScroller != null; + final boolean inflated = mStackScroller != null && mStatusBarWindowManager != null; // The system wallpaper defines if QS should be light or dark. WallpaperColors systemColors = mColorExtractor diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 5001d4ffa13c..b49ad46c2100 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -173,7 +173,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb || mStatusBar.isFullScreenUserSwitcherState()) { mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } else if (mShowing && !mDozing) { - if (!isWakeAndUnlocking()) { + if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) { mBouncer.setExpansion(expansion); } if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index a79a41b07797..fa763c852cdf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -37,6 +37,7 @@ import android.os.IBinder; import android.os.SystemClock; import android.util.AttributeSet; import android.view.ActionMode; +import android.view.DisplayCutout; import android.view.InputDevice; import android.view.InputQueue; import android.view.KeyEvent; @@ -75,6 +76,7 @@ public class StatusBarWindowView extends FrameLayout { private NotificationStackScrollLayout mStackScrollLayout; private NotificationPanelView mNotificationPanel; private View mBrightnessMirror; + private PhoneStatusBarView mStatusBarView; private int mRightInset = 0; private int mLeftInset = 0; @@ -94,6 +96,12 @@ public class StatusBarWindowView extends FrameLayout { private boolean mExpandAnimationRunning; private boolean mExpandAnimationPending; + /** + * If set to true, the current gesture started below the notch and we need to dispatch touch + * events manually as it's outside of the regular view bounds. + */ + private boolean mExpandingBelowNotch; + public StatusBarWindowView(Context context, AttributeSet attrs) { super(context, attrs); setMotionEventSplittingEnabled(false); @@ -112,10 +120,21 @@ public class StatusBarWindowView extends FrameLayout { boolean paddingChanged = insets.top != getPaddingTop() || insets.bottom != getPaddingBottom(); + int rightCutout = 0; + int leftCutout = 0; + DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout(); + if (displayCutout != null) { + leftCutout = displayCutout.getSafeInsetLeft(); + rightCutout = displayCutout.getSafeInsetRight(); + } + + int targetLeft = Math.max(insets.left, leftCutout); + int targetRight = Math.max(insets.right, rightCutout); + // Super-special right inset handling, because scrims and backdrop need to ignore it. - if (insets.right != mRightInset || insets.left != mLeftInset) { - mRightInset = insets.right; - mLeftInset = insets.left; + if (targetRight != mRightInset || targetLeft != mLeftInset) { + mRightInset = targetRight; + mLeftInset = targetLeft; applyMargins(); } // Drop top inset, and pass through bottom inset. @@ -186,6 +205,10 @@ public class StatusBarWindowView extends FrameLayout { } } + public void setStatusBarView(PhoneStatusBarView statusBarView) { + mStatusBarView = statusBarView; + } + public void setService(StatusBar service) { mService = service; setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, mService)); @@ -258,7 +281,16 @@ public class StatusBarWindowView extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN; + boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP; boolean isCancel = ev.getActionMasked() == MotionEvent.ACTION_CANCEL; + + // Reset manual touch dispatch state here but make sure the UP/CANCEL event still gets + // delivered. + boolean expandingBelowNotch = mExpandingBelowNotch; + if (isUp || isCancel) { + mExpandingBelowNotch = false; + } + if (!isCancel && mService.shouldIgnoreTouch()) { return false; } @@ -291,6 +323,17 @@ public class StatusBarWindowView extends FrameLayout { mService.mDozeScrimController.extendPulse(); } + // In case we start outside of the view bounds (below the status bar), we need to dispatch + // the touch manually as the view system can't accomodate for touches outside of the + // regular view bounds. + if (isDown && ev.getY() >= mBottom) { + mExpandingBelowNotch = true; + expandingBelowNotch = true; + } + if (expandingBelowNotch) { + return mStatusBarView.dispatchTouchEvent(ev); + } + return super.dispatchTouchEvent(ev); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 2031b27c93f2..59b376f311fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -113,10 +113,6 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode @Override public void addCallback(Callback callback) { - if (callback == null) { - Slog.e(TAG, "Attempted to add a null callback."); - return; - } mCallbacks.add(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java index c26568ea00b3..e80f48309bbb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java @@ -137,6 +137,10 @@ public class AnimationFilter { // to look nice customDelay = StackStateAnimator.ANIMATION_DELAY_HEADS_UP_CLICKED + StackStateAnimator.ANIMATION_DELAY_HEADS_UP; + } else if (ev.animationType == NotificationStackScrollLayout.AnimationEvent + .ANIMATION_TYPE_PULSE_APPEAR || ev.animationType == + NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) { + customDelay = StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR / 2; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 9c26c69045d5..9d0d295a26ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -101,6 +101,7 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpUtil; @@ -140,7 +141,6 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mSwipingInProgress; private int mCurrentStackHeight = Integer.MAX_VALUE; private final Paint mBackgroundPaint = new Paint(); - private final Path mBackgroundPath = new Path(); private final boolean mShouldDrawNotificationBackground; private float mExpandedHeight; @@ -376,6 +376,11 @@ public class NotificationStackScrollLayout extends ViewGroup private View mForcedScroll; private View mNeedingPulseAnimation; private float mDarkAmount = 0f; + + /** + * How fast the background scales in the X direction as a factor of the Y expansion. + */ + private float mBackgroundXFactor = 1f; private static final Property<NotificationStackScrollLayout, Float> DARK_AMOUNT = new FloatProperty<NotificationStackScrollLayout>("darkAmount") { @Override @@ -416,6 +421,8 @@ public class NotificationStackScrollLayout extends ViewGroup private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>(); private int mHeadsUpInset; private HeadsUpAppearanceController mHeadsUpAppearanceController; + private NotificationIconAreaController mIconAreaController; + private float mVerticalPanelTranslation; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -532,10 +539,16 @@ public class NotificationStackScrollLayout extends ViewGroup final int lockScreenRight = getWidth() - mSidePaddings; final int lockScreenTop = mCurrentBounds.top; final int lockScreenBottom = mCurrentBounds.bottom; - final int darkLeft = getWidth() / 2 - mSeparatorWidth / 2; - final int darkRight = darkLeft + mSeparatorWidth; - final int darkTop = (int) (mRegularTopPadding + mSeparatorThickness / 2f); - final int darkBottom = darkTop + mSeparatorThickness; + int separatorWidth = 0; + int separatorThickness = 0; + if (mIconAreaController.hasShelfIconsWhenFullyDark()) { + separatorThickness = mSeparatorThickness; + separatorWidth = mSeparatorWidth; + } + final int darkLeft = getWidth() / 2 - separatorWidth / 2; + final int darkRight = darkLeft + separatorWidth; + final int darkTop = (int) (mRegularTopPadding + separatorThickness / 2f); + final int darkBottom = darkTop + separatorThickness; if (mAmbientState.hasPulsingNotifications()) { // No divider, we have a notification icon instead @@ -548,7 +561,7 @@ public class NotificationStackScrollLayout extends ViewGroup float inverseDark = 1 - mDarkAmount; float yProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(inverseDark); float xProgress = Interpolators.FAST_OUT_SLOW_IN - .getInterpolation(inverseDark * 2f); + .getInterpolation(inverseDark * mBackgroundXFactor); mBackgroundAnimationRect.set( (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress), @@ -2041,11 +2054,9 @@ public class NotificationStackScrollLayout extends ViewGroup } private int getScrollRange() { - int contentHeight = getContentHeight(); - int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight); + int scrollRange = Math.max(0, mContentHeight - mMaxLayoutHeight); int imeInset = getImeInset(); - scrollRange += Math.min(imeInset, Math.max(0, - getContentHeight() - (getHeight() - imeInset))); + scrollRange += Math.min(imeInset, Math.max(0, mContentHeight - (getHeight() - imeInset))); return scrollRange; } @@ -2146,10 +2157,6 @@ public class NotificationStackScrollLayout extends ViewGroup return count; } - public int getContentHeight() { - return mContentHeight; - } - private void updateContentHeight() { int height = 0; float previousPaddingRequest = mPaddingBetweenElements; @@ -2213,7 +2220,11 @@ public class NotificationStackScrollLayout extends ViewGroup } } mIntrinsicContentHeight = height; - mContentHeight = height + mTopPadding + mBottomMargin; + + // We don't want to use the toppadding since that might be interpolated and we want + // to take the final value of the animation. + int topPadding = mAmbientState.isFullyDark() ? mDarkTopPadding : mRegularTopPadding; + mContentHeight = height + topPadding + mBottomMargin; updateScrollability(); clampScrollPosition(); mAmbientState.setLayoutMaxHeight(mContentHeight); @@ -3993,8 +4004,13 @@ public class NotificationStackScrollLayout extends ViewGroup notifyHeightChangeListener(mShelf); } - private void updateAntiBurnInTranslation() { - setTranslationX(mAntiBurnInOffsetX * mDarkAmount); + private void updatePanelTranslation() { + setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mDarkAmount); + } + + public void setVerticalPanelTranslation(float verticalPanelTranslation) { + mVerticalPanelTranslation = verticalPanelTranslation; + updatePanelTranslation(); } /** @@ -4011,16 +4027,20 @@ public class NotificationStackScrollLayout extends ViewGroup mDarkAmount = darkAmount; boolean wasFullyDark = mAmbientState.isFullyDark(); mAmbientState.setDarkAmount(darkAmount); - if (mAmbientState.isFullyDark() != wasFullyDark) { + boolean nowFullyDark = mAmbientState.isFullyDark(); + if (nowFullyDark != wasFullyDark) { updateContentHeight(); DozeParameters dozeParameters = DozeParameters.getInstance(mContext); - if (mAmbientState.isFullyDark() && dozeParameters.shouldControlScreenOff()) { + if (nowFullyDark && dozeParameters.shouldControlScreenOff()) { mShelf.fadeInTranslating(); } + if (mIconAreaController != null) { + mIconAreaController.setFullyDark(nowFullyDark); + } } updateAlgorithmHeightAndPadding(); updateBackgroundDimming(); - updateAntiBurnInTranslation(); + updatePanelTranslation(); requestChildrenUpdate(); } @@ -4028,21 +4048,37 @@ public class NotificationStackScrollLayout extends ViewGroup return mDarkAmount; } + /** + * Cancel any previous dark animations - to avoid race conditions - and creates a new one. + * This function also sets {@code mBackgroundXFactor} based on the current {@code mDarkAmount}. + */ private void startDarkAmountAnimation() { - ObjectAnimator darkAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount, - mAmbientState.isDark() ? 1f : 0); - darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP); - darkAnimator.setInterpolator(Interpolators.ALPHA_IN); - darkAnimator.addListener(new AnimatorListenerAdapter() { + boolean dark = mAmbientState.isDark(); + if (mDarkAmountAnimator != null) { + mDarkAmountAnimator.cancel(); + } + + long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP; + // Longer animation when sleeping with more than 1 notification + if (dark && getNotGoneChildCount() > 2) { + duration *= 1.2f; + } + + mDarkAmountAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount, + dark ? 1f : 0); + // We only swap the scaling factor if we're fully dark or fully awake to avoid + // interpolation issues when playing with the power button. + if (mDarkAmount == 0 || mDarkAmount == 1) { + mBackgroundXFactor = dark ? 2.5f : 1.5f; + } + mDarkAmountAnimator.setDuration(duration); + mDarkAmountAnimator.setInterpolator(Interpolators.LINEAR); + mDarkAmountAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mDarkAmountAnimator = null; } }); - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); - } - mDarkAmountAnimator = darkAnimator; mDarkAmountAnimator.start(); } @@ -4572,7 +4608,7 @@ public class NotificationStackScrollLayout extends ViewGroup public void setAntiBurnInOffsetX(int antiBurnInOffsetX) { mAntiBurnInOffsetX = antiBurnInOffsetX; - updateAntiBurnInTranslation(); + updatePanelTranslation(); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -4618,6 +4654,10 @@ public class NotificationStackScrollLayout extends ViewGroup mHeadsUpAppearanceController = headsUpAppearanceController; } + public void setIconAreaController(NotificationIconAreaController controller) { + mIconAreaController = controller; + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ @@ -5031,11 +5071,13 @@ public class NotificationStackScrollLayout extends ViewGroup // ANIMATION_TYPE_PULSE_APPEAR new AnimationFilter() .animateAlpha() + .hasDelays() .animateY(), // ANIMATION_TYPE_PULSE_DISAPPEAR new AnimationFilter() .animateAlpha() + .hasDelays() .animateY(), }; @@ -5099,10 +5141,10 @@ public class NotificationStackScrollLayout extends ViewGroup StackStateAnimator.ANIMATION_DURATION_STANDARD, // ANIMATION_TYPE_PULSE_APPEAR - KeyguardSliceView.DEFAULT_ANIM_DURATION, + StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR, // ANIMATION_TYPE_PULSE_DISAPPEAR - KeyguardSliceView.DEFAULT_ANIM_DURATION / 2, + StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR / 2, }; static final int ANIMATION_TYPE_ADD = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index a75d40f92011..b83a09dd02ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -24,6 +24,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.Interpolator; +import com.android.keyguard.KeyguardSliceView; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.ExpandableNotificationRow; @@ -51,6 +52,8 @@ public class StackStateAnimator { = (int) (ANIMATION_DURATION_HEADS_UP_APPEAR * HeadsUpAppearInterpolator.getFractionUntilOvershoot()); public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 300; + public static final int ANIMATION_DURATION_PULSE_APPEAR = + KeyguardSliceView.DEFAULT_ANIM_DURATION; public static final int ANIMATION_DURATION_BLOCKING_HELPER_FADE = 240; public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80; public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32; @@ -430,15 +433,26 @@ public class StackStateAnimator { } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR) { ExpandableViewState viewState = finalState.getViewStateForView(changingView); - mTmpState.copyFrom(viewState); - mTmpState.yTranslation += mPulsingAppearingTranslation; - mTmpState.alpha = 0; - mTmpState.applyToView(changingView); + if (viewState != null) { + mTmpState.copyFrom(viewState); + mTmpState.yTranslation += mPulsingAppearingTranslation; + mTmpState.alpha = 0; + mTmpState.applyToView(changingView); + } } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) { ExpandableViewState viewState = finalState.getViewStateForView(changingView); - viewState.yTranslation += mPulsingAppearingTranslation; - viewState.alpha = 0; + if (viewState != null) { + viewState.alpha = 0; + // We want to animate the alpha away before the view starts translating, + // otherwise everything will overlap and look xtra ugly. + float originalYTranslation = viewState.yTranslation; + viewState.yTranslation = changingView.getTranslationY(); + mAnimationFilter.animateAlpha = true; + mAnimationProperties.duration = ANIMATION_DURATION_PULSE_APPEAR / 2; + viewState.animateTo(changingView, mAnimationProperties); + viewState.yTranslation = originalYTranslation; + } } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) { // This item is added, initialize it's properties. diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index eca612776f21..6812410c851c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -26,11 +26,14 @@ public class Utils { /** * Allows lambda iteration over a list. It is done in reverse order so it is safe - * to add or remove items during the iteration. + * to add or remove items during the iteration. Skips over null items. */ public static <T> void safeForeach(List<T> list, Consumer<T> c) { for (int i = list.size() - 1; i >= 0; i--) { - c.accept(list.get(i)); + T item = list.get(i); + if (item != null) { + c.accept(item); + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java index 8153953a0c38..13dc36da2698 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java +++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java @@ -93,7 +93,7 @@ public class SysuiColorExtractorTests extends SysuiTestCase { SysuiColorExtractor extractor = getTestableExtractor(colors); simulateEvent(extractor); extractor.setWallpaperVisible(true); - extractor.setMediaBackdropVisible(true); + extractor.setHasBackdrop(true); ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java index 64507be764de..bb67d6e03a9d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java @@ -16,7 +16,7 @@ package com.android.systemui.doze; -import static org.junit.Assert.assertTrue; +import static junit.framework.TestCase.assertEquals; import android.os.UserHandle; import android.provider.Settings; @@ -42,14 +42,15 @@ public class DozeConfigurationTest extends SysuiTestCase { } @Test - public void alwaysOn_onByDefault() throws Exception { + public void alwaysOn_followsConfigByDefault() throws Exception { if (!mDozeConfig.alwaysOnAvailable()) { return; } Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON, null); - - assertTrue(mDozeConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)); + boolean defaultValue = mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_dozeAlwaysOnEnabled); + assertEquals(mDozeConfig.alwaysOnEnabled(UserHandle.USER_CURRENT), defaultValue); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index e95702c5ab91..89d562a2099c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -44,7 +44,6 @@ import android.view.View; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.util.function.TriConsumer; -import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.util.wakelock.WakeLock; @@ -94,6 +93,7 @@ public class ScrimControllerTest extends SysuiTestCase { mScrimInFrontColor = scrimInFrontColor; }, visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager); + mScrimController.setHasBackdrop(false); } @Test @@ -140,12 +140,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() { - ScrimState.AOD.mKeyguardUpdateMonitor = new KeyguardUpdateMonitor(getContext()) { - @Override - public boolean hasLockscreenWallpaper() { - return true; - } - }; + mScrimController.setHasBackdrop(true); mScrimController.setWallpaperSupportsAmbientMode(true); mScrimController.transitionTo(ScrimState.AOD); mScrimController.finishAnimationsImmediately(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 85135ac77b3c..94ab9d2a7d04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -177,6 +177,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mBouncer, never()).setExpansion(anyFloat()); } + @Test + public void onPanelExpansionChanged_neverTranslatesBouncerWhenLaunchingApp() { + when(mStatusBar.isInLaunchTransition()).thenReturn(true); + mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE, + false /* tracking */); + verify(mBouncer, never()).setExpansion(anyFloat()); + } + private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { public TestableStatusBarKeyguardViewManager(Context context, diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 36ece79ec095..3c94a344b430 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -898,6 +898,10 @@ public class ConnectivityService extends IConnectivityManager.Stub public boolean isTetheringSupported() { return ConnectivityService.this.isTetheringSupported(); } + @Override + public NetworkRequest getDefaultNetworkRequest() { + return mDefaultRequest; + } }; return new Tethering(mContext, mNetd, mStatsService, mPolicyManager, IoThread.get().getLooper(), new MockableSystemProperties(), @@ -915,7 +919,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkRequest createDefaultInternetRequestForTransport( int transportType, NetworkRequest.Type type) { - NetworkCapabilities netCap = new NetworkCapabilities(); + final NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); if (transportType > -1) { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 607db4efb63e..ad9fa40e0ab8 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1588,10 +1588,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { // Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast. intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + // Create a version of the intent with the number always populated. Intent intentWithPhoneNumber = new Intent(intent); - if (!TextUtils.isEmpty(incomingNumber)) { - intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); - } + intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); + // Send broadcast twice, once for apps that have PRIVILEGED permission and once for those // that have the runtime one mContext.sendBroadcastAsUser(intentWithPhoneNumber, UserHandle.ALL, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 928f6ef9934a..385d038ce68b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2207,6 +2207,9 @@ public class ActivityManagerService extends IActivityManager.Stub } } callbacks.finishBroadcast(); + // We have to clean up the RemoteCallbackList here, because otherwise it will + // needlessly hold the enclosed callbacks until the remote process dies. + callbacks.kill(); } break; case UPDATE_TIME_ZONE: { synchronized (ActivityManagerService.this) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index cc7a2308834e..aea29ac066a3 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1654,13 +1654,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) { if (!mStackSupervisor.mStoppingActivities.contains(r)) { mStackSupervisor.mStoppingActivities.add(r); - - // Some activity is waiting for another activity to become visible before it's being - // stopped, which means that we also want to wait with stopping this one to avoid - // flickers. - if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty()) { - mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r); - } } // If we already have a few activities waiting to stop, then give up diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 0b9832d90f7d..87dd75608379 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -236,7 +236,6 @@ public class AudioService extends IAudioService.Stub private static final int MSG_PERSIST_RINGER_MODE = 3; private static final int MSG_AUDIO_SERVER_DIED = 4; private static final int MSG_PLAY_SOUND_EFFECT = 5; - private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6; private static final int MSG_LOAD_SOUND_EFFECTS = 7; private static final int MSG_SET_FORCE_USE = 8; private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; @@ -268,6 +267,7 @@ public class AudioService extends IAudioService.Stub private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103; private static final int MSG_DISABLE_AUDIO_FOR_UID = 104; private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105; + private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106; // end of messages handled under wakelock private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; @@ -2632,6 +2632,7 @@ public class AudioService extends IAudioService.Stub broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode); } + @GuardedBy("mSettingsLock") private void muteRingerModeStreams() { // Mute stream if not previously muted by ringer mode and (ringer mode // is not RINGER_MODE_NORMAL OR stream is zen muted) and stream is affected by ringer mode. @@ -2719,10 +2720,9 @@ public class AudioService extends IAudioService.Stub synchronized(mSettingsLock) { change = mRingerMode != ringerMode; mRingerMode = ringerMode; + muteRingerModeStreams(); } - muteRingerModeStreams(); - // Post a persist ringer mode msg if (persist) { sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, @@ -4521,13 +4521,21 @@ public class AudioService extends IAudioService.Stub } synchronized (mLastDeviceConnectMsgTime) { long time = SystemClock.uptimeMillis() + delay; - handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time); - if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE || - msg == MSG_SET_A2DP_SRC_CONNECTION_STATE || - msg == MSG_SET_A2DP_SINK_CONNECTION_STATE || - msg == MSG_SET_HEARING_AID_CONNECTION_STATE) { + + if (msg == MSG_SET_A2DP_SRC_CONNECTION_STATE || + msg == MSG_SET_A2DP_SINK_CONNECTION_STATE || + msg == MSG_SET_HEARING_AID_CONNECTION_STATE || + msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE || + msg == MSG_A2DP_DEVICE_CONFIG_CHANGE || + msg == MSG_BTA2DP_DOCK_TIMEOUT) { + if (mLastDeviceConnectMsgTime >= time) { + // add a little delay to make sure messages are ordered as expected + time = mLastDeviceConnectMsgTime + 30; + } mLastDeviceConnectMsgTime = time; } + + handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time); } } @@ -4689,6 +4697,13 @@ public class AudioService extends IAudioService.Stub } else { delay = 0; } + + if (DEBUG_DEVICES) { + Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device + + " state: " + state + " delay(ms): " + delay + + " suppressNoisyIntent: " + suppressNoisyIntent); + } + queueMsgUnderWakeLock(mAudioHandler, (profile == BluetoothProfile.A2DP ? MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE), @@ -5597,6 +5612,7 @@ public class AudioService extends IAudioService.Stub synchronized (mConnectedDevices) { makeA2dpDeviceUnavailableNow( (String) msg.obj ); } + mAudioEventWakeLock.release(); break; case MSG_SET_FORCE_USE: @@ -5827,6 +5843,9 @@ public class AudioService extends IAudioService.Stub // must be called synchronized on mConnectedDevices private void makeA2dpDeviceUnavailableNow(String address) { + if (address == null) { + return; + } synchronized (mA2dpAvrcpLock) { mAvrcpAbsVolSupported = false; } @@ -5836,6 +5855,9 @@ public class AudioService extends IAudioService.Stub makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); // Remove A2DP routes as well setCurrentAudioRouteName(null); + if (mDockAddress == address) { + mDockAddress = null; + } } // must be called synchronized on mConnectedDevices @@ -5847,9 +5869,12 @@ public class AudioService extends IAudioService.Stub mConnectedDevices.remove( makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); // send the delayed message to make the device unavailable later - Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); - mAudioHandler.sendMessageDelayed(msg, delayMs); - + queueMsgUnderWakeLock(mAudioHandler, + MSG_BTA2DP_DOCK_TIMEOUT, + 0, + 0, + address, + delayMs); } // must be called synchronized on mConnectedDevices @@ -5921,7 +5946,8 @@ public class AudioService extends IAudioService.Stub private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume) { if (DEBUG_DEVICES) { - Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state); + Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state + + " is dock: "+btDevice.isBluetoothDock()); } if (btDevice == null) { return; @@ -5958,7 +5984,7 @@ public class AudioService extends IAudioService.Stub } else { // this could be a connection of another A2DP device before the timeout of // a dock: cancel the dock timeout, and make the dock unavailable now - if(hasScheduledA2dpDockTimeout()) { + if (hasScheduledA2dpDockTimeout() && mDockAddress != null) { cancelA2dpDeviceTimeout(); makeA2dpDeviceUnavailableNow(mDockAddress); } @@ -6177,17 +6203,6 @@ public class AudioService extends IAudioService.Stub } } - if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) || - mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) || - mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) || - mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) { - synchronized (mLastDeviceConnectMsgTime) { - long time = SystemClock.uptimeMillis(); - if (mLastDeviceConnectMsgTime > time) { - delay = (int)(mLastDeviceConnectMsgTime - time) + 30; - } - } - } return delay; } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index df6a6f8bdcc1..51059415a262 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1350,8 +1350,11 @@ public class Tethering extends BaseNetworkObserver { // do not currently know how to watch for changes in DUN settings. maybeUpdateConfiguration(); - final NetworkState ns = mUpstreamNetworkMonitor.selectPreferredUpstreamType( - mConfig.preferredUpstreamIfaceTypes); + final TetheringConfiguration config = mConfig; + final NetworkState ns = (config.chooseUpstreamAutomatically) + ? mUpstreamNetworkMonitor.getCurrentPreferredUpstream() + : mUpstreamNetworkMonitor.selectPreferredUpstreamType( + config.preferredUpstreamIfaceTypes); if (ns == null) { if (tryCell) { mUpstreamNetworkMonitor.registerMobileNetworkRequest(); @@ -1380,9 +1383,7 @@ public class Tethering extends BaseNetworkObserver { } notifyDownstreamsOfNewUpstreamIface(ifaces); if (ns != null && pertainsToCurrentUpstream(ns)) { - // If we already have NetworkState for this network examine - // it immediately, because there likely will be no second - // EVENT_ON_AVAILABLE (it was already received). + // If we already have NetworkState for this network update it immediately. handleNewUpstreamNetworkState(ns); } else if (mCurrentUpstreamIfaceSet == null) { // There are no available upstream networks. @@ -1498,15 +1499,6 @@ public class Tethering extends BaseNetworkObserver { } switch (arg1) { - case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE: - // The default network changed, or DUN connected - // before this callback was processed. Updates - // for the current NetworkCapabilities and - // LinkProperties have been requested (default - // request) or are being sent shortly (DUN). Do - // nothing until they arrive; if no updates - // arrive there's nothing to do. - break; case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES: handleNewUpstreamNetworkState(ns); break; @@ -1539,7 +1531,7 @@ public class Tethering extends BaseNetworkObserver { } mSimChange.startListening(); - mUpstreamNetworkMonitor.start(); + mUpstreamNetworkMonitor.start(mDeps.getDefaultNetworkRequest()); // TODO: De-duplicate with updateUpstreamWanted() below. if (upstreamWanted()) { diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java index 454c579ed0a7..dd9fe05b50ff 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -27,6 +27,7 @@ import static com.android.internal.R.array.config_tether_dhcp_range; import static com.android.internal.R.array.config_tether_usb_regexs; import static com.android.internal.R.array.config_tether_upstream_types; import static com.android.internal.R.array.config_tether_wifi_regexs; +import static com.android.internal.R.bool.config_tether_upstream_automatic; import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui; import android.content.Context; @@ -86,6 +87,7 @@ public class TetheringConfiguration { public final String[] tetherableBluetoothRegexs; public final int dunCheck; public final boolean isDunRequired; + public final boolean chooseUpstreamAutomatically; public final Collection<Integer> preferredUpstreamIfaceTypes; public final String[] dhcpRanges; public final String[] defaultIPv4DNS; @@ -106,6 +108,7 @@ public class TetheringConfiguration { dunCheck = checkDunRequired(ctx); configLog.log("DUN check returned: " + dunCheckString(dunCheck)); + chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck); isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN); @@ -142,6 +145,8 @@ public class TetheringConfiguration { pw.print("isDunRequired: "); pw.println(isDunRequired); + pw.print("chooseUpstreamAutomatically: "); + pw.println(chooseUpstreamAutomatically); dumpStringArray(pw, "preferredUpstreamIfaceTypes", preferredUpstreamNames(preferredUpstreamIfaceTypes)); @@ -160,6 +165,7 @@ public class TetheringConfiguration { sj.add(String.format("tetherableBluetoothRegexs:%s", makeString(tetherableBluetoothRegexs))); sj.add(String.format("isDunRequired:%s", isDunRequired)); + sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically)); sj.add(String.format("preferredUpstreamIfaceTypes:%s", makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes)))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); @@ -286,6 +292,14 @@ public class TetheringConfiguration { } } + private static boolean getResourceBoolean(Context ctx, int resId) { + try { + return ctx.getResources().getBoolean(resId); + } catch (Resources.NotFoundException e404) { + return false; + } + } + private static String[] getResourceStringArray(Context ctx, int resId) { try { final String[] strArray = ctx.getResources().getStringArray(resId); diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java index 0ac7a36e3ffc..605ee9c8ee2e 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -18,6 +18,7 @@ package com.android.server.connectivity.tethering; import android.content.Context; import android.net.INetd; +import android.net.NetworkRequest; import android.net.ip.RouterAdvertisementDaemon; import android.net.util.InterfaceParams; import android.net.util.NetdService; @@ -64,4 +65,8 @@ public class TetheringDependencies { public boolean isTetheringSupported() { return true; } + + public NetworkRequest getDefaultNetworkRequest() { + return null; + } } diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index 34132910ca86..f488be70af49 100644 --- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -20,6 +20,9 @@ import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import android.content.Context; import android.os.Handler; @@ -74,14 +77,13 @@ public class UpstreamNetworkMonitor { private static final boolean DBG = false; private static final boolean VDBG = false; - public static final int EVENT_ON_AVAILABLE = 1; - public static final int EVENT_ON_CAPABILITIES = 2; - public static final int EVENT_ON_LINKPROPERTIES = 3; - public static final int EVENT_ON_LOST = 4; + public static final int EVENT_ON_CAPABILITIES = 1; + public static final int EVENT_ON_LINKPROPERTIES = 2; + public static final int EVENT_ON_LOST = 3; public static final int NOTIFY_LOCAL_PREFIXES = 10; private static final int CALLBACK_LISTEN_ALL = 1; - private static final int CALLBACK_TRACK_DEFAULT = 2; + private static final int CALLBACK_DEFAULT_INTERNET = 2; private static final int CALLBACK_MOBILE_REQUEST = 3; private final Context mContext; @@ -117,7 +119,7 @@ public class UpstreamNetworkMonitor { mCM = cm; } - public void start() { + public void start(NetworkRequest defaultNetworkRequest) { stop(); final NetworkRequest listenAllRequest = new NetworkRequest.Builder() @@ -125,8 +127,16 @@ public class UpstreamNetworkMonitor { mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL); cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler); - mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT); - cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler); + if (defaultNetworkRequest != null) { + // This is not really a "request", just a way of tracking the system default network. + // It's guaranteed not to actually bring up any networks because it's the same request + // as the ConnectivityService default request, and thus shares fate with it. We can't + // use registerDefaultNetworkCallback because it will not track the system default + // network if there is a VPN that applies to our UID. + final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest); + mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); + cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler); + } } public void stop() { @@ -225,6 +235,20 @@ public class UpstreamNetworkMonitor { return typeStatePair.ns; } + // Returns null if no current upstream available. + public NetworkState getCurrentPreferredUpstream() { + final NetworkState dfltState = (mDefaultInternetNetwork != null) + ? mNetworkMap.get(mDefaultInternetNetwork) + : null; + if (!mDunRequired) return dfltState; + + if (isNetworkUsableAndNotCellular(dfltState)) return dfltState; + + // Find a DUN network. Note that code in Tethering causes a DUN request + // to be filed, but this might be moved into this class in future. + return findFirstDunNetwork(mNetworkMap.values()); + } + public void setCurrentUpstream(Network upstream) { mTetheringUpstreamNetwork = upstream; } @@ -233,72 +257,16 @@ public class UpstreamNetworkMonitor { return (Set<IpPrefix>) mLocalPrefixes.clone(); } - private void handleAvailable(int callbackType, Network network) { - if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network); - - if (!mNetworkMap.containsKey(network)) { - mNetworkMap.put(network, - new NetworkState(null, null, null, network, null, null)); - } - - // Always request whatever extra information we can, in case this - // was already up when start() was called, in which case we would - // not have been notified of any information that had not changed. - switch (callbackType) { - case CALLBACK_LISTEN_ALL: - break; - - case CALLBACK_TRACK_DEFAULT: - if (mDefaultNetworkCallback == null) { - // The callback was unregistered in the interval between - // ConnectivityService enqueueing onAvailable() and our - // handling of it here on the mHandler thread. - // - // Clean-up of this network entry is deferred to the - // handling of onLost() by other callbacks. - // - // These request*() calls can be deleted post oag/339444. - return; - } - mDefaultInternetNetwork = network; - break; - - case CALLBACK_MOBILE_REQUEST: - if (mMobileNetworkCallback == null) { - // The callback was unregistered in the interval between - // ConnectivityService enqueueing onAvailable() and our - // handling of it here on the mHandler thread. - // - // Clean-up of this network entry is deferred to the - // handling of onLost() by other callbacks. - return; - } - break; - } - - // Requesting updates for mListenAllCallback is not currently possible - // because it's a "listen". Two possible solutions to getting updates - // about networks without waiting for a change (which might never come) - // are: - // - // [1] extend request{NetworkCapabilities,LinkProperties}() to - // take a Network argument and have ConnectivityService do - // what's required (if the network satisfies the request) - // - // [2] explicitly file a NetworkRequest for each connectivity type - // listed as a preferred upstream and wait for these callbacks - // to be notified (requires tracking many more callbacks). - // - // Until this is addressed, networks that exist prior to the "listen" - // registration and which do not subsequently change will not cause - // us to learn their NetworkCapabilities nor their LinkProperties. + private void handleAvailable(Network network) { + if (mNetworkMap.containsKey(network)) return; - // TODO: If sufficient information is available to select a more - // preferable upstream, do so now and notify the target. - notifyTarget(EVENT_ON_AVAILABLE, network); + if (VDBG) Log.d(TAG, "onAvailable for " + network); + mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null)); } - private void handleNetCap(Network network, NetworkCapabilities newNc) { + private void handleNetCap(int callbackType, Network network, NetworkCapabilities newNc) { + if (callbackType == CALLBACK_DEFAULT_INTERNET) mDefaultInternetNetwork = network; + final NetworkState prev = mNetworkMap.get(network); if (prev == null || newNc.equals(prev.networkCapabilities)) { // Ignore notifications about networks for which we have not yet @@ -360,13 +328,17 @@ public class UpstreamNetworkMonitor { } private void handleLost(int callbackType, Network network) { - if (callbackType == CALLBACK_TRACK_DEFAULT) { + if (network.equals(mDefaultInternetNetwork)) { mDefaultInternetNetwork = null; - // Receiving onLost() for a default network does not necessarily - // mean the network is gone. We wait for a separate notification - // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before - // clearing all state. - return; + // There are few TODOs within ConnectivityService's rematching code + // pertaining to spurious onLost() notifications. + // + // TODO: simplify this, probably if favor of code that: + // - selects a new upstream if mTetheringUpstreamNetwork has + // been lost (by any callback) + // - deletes the entry from the map only when the LISTEN_ALL + // callback gets notified. + if (callbackType == CALLBACK_DEFAULT_INTERNET) return; } if (!mNetworkMap.containsKey(network)) { @@ -416,17 +388,19 @@ public class UpstreamNetworkMonitor { @Override public void onAvailable(Network network) { - handleAvailable(mCallbackType, network); + handleAvailable(network); } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { - handleNetCap(network, newNc); + handleNetCap(mCallbackType, network, newNc); } @Override public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { handleLinkProp(network, newLp); + // TODO(b/110335330): reduce the number of times this is called by + // only recomputing on the LISTEN_ALL callback. recomputeLocalPrefixes(); } @@ -443,6 +417,8 @@ public class UpstreamNetworkMonitor { @Override public void onLost(Network network) { handleLost(mCallbackType, network); + // TODO(b/110335330): reduce the number of times this is called by + // only recomputing on the LISTEN_ALL callback. recomputeLocalPrefixes(); } } @@ -509,4 +485,31 @@ public class UpstreamNetworkMonitor { if (nc == null || !nc.hasSignalStrength()) return "unknown"; return Integer.toString(nc.getSignalStrength()); } + + private static boolean isCellular(NetworkState ns) { + return (ns != null) && isCellular(ns.networkCapabilities); + } + + private static boolean isCellular(NetworkCapabilities nc) { + return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR) && + nc.hasCapability(NET_CAPABILITY_NOT_VPN); + } + + private static boolean hasCapability(NetworkState ns, int netCap) { + return (ns != null) && (ns.networkCapabilities != null) && + ns.networkCapabilities.hasCapability(netCap); + } + + private static boolean isNetworkUsableAndNotCellular(NetworkState ns) { + return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null) && + !isCellular(ns.networkCapabilities); + } + + private static NetworkState findFirstDunNetwork(Iterable<NetworkState> netStates) { + for (NetworkState ns : netStates) { + if (isCellular(ns) && hasCapability(ns, NET_CAPABILITY_DUN)) return ns; + } + + return null; + } } diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java index 4f53ed49002b..33525fdc52d2 100644 --- a/services/core/java/com/android/server/display/ColorFade.java +++ b/services/core/java/com/android/server/display/ColorFade.java @@ -46,6 +46,7 @@ import android.view.SurfaceSession; import libcore.io.Streams; import com.android.server.LocalServices; +import com.android.server.policy.WindowManagerPolicy; /** * <p> @@ -63,7 +64,7 @@ final class ColorFade { // The layer for the electron beam surface. // This is currently hardcoded to be one layer above the boot animation. - private static final int COLOR_FADE_LAYER = 0x40000001; + private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER; // The number of frames to draw when preparing the animation so that it will // be ready to run smoothly. We use 3 frames because we are triple-buffered. diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 8d730b4f7fc0..0ec1f9ccd37b 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -254,7 +254,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt // 1 second, or 1 Hz frequency. private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000; // Default update duration in milliseconds for REQUEST_LOCATION. - private static final long LOCATION_UPDATE_DURATION_MILLIS = 0; + private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000; /** simpler wrapper for ProviderRequest + Worksource */ private static class GpsRequest { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0897b8a52ad6..cafc6fce6901 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4525,6 +4525,15 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") @VisibleForTesting protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) { + // Ignore summary updates because we don't display most of the information. + if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) { + if (DEBUG_INTERRUPTIVENESS) { + Log.v(TAG, "INTERRUPTIVENESS: " + + r.getKey() + " is not interruptive: summary"); + } + return false; + } + if (old == null) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " @@ -4562,15 +4571,6 @@ public class NotificationManagerService extends SystemService { return false; } - // Ignore summary updates because we don't display most of the information. - if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) { - if (DEBUG_INTERRUPTIVENESS) { - Log.v(TAG, "INTERRUPTIVENESS: " - + r.getKey() + " is not interruptive: summary"); - } - return false; - } - final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); if (!Objects.equals(oldTitle, newTitle)) { diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 0f3f44eae2d3..39d0bf58c3b1 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -95,6 +95,7 @@ public final class NotificationRecord { static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final int MAX_LOGTAG_LENGTH = 35; final StatusBarNotification sbn; + IActivityManager mAm; final int mTargetSdkVersion; final int mOriginalFlags; private final Context mContext; @@ -174,6 +175,7 @@ public final class NotificationRecord { this.sbn = sbn; mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class) .getPackageTargetSdkVersion(sbn.getPackageName()); + mAm = ActivityManager.getService(); mOriginalFlags = sbn.getNotification().flags; mRankingTimeMs = calculateRankingTimeMs(0L); mCreationTimeMs = sbn.getPostTime(); @@ -1036,16 +1038,17 @@ public final class NotificationRecord { * Collect all {@link Uri} that should have permission granted to whoever * will be rendering it. */ - private void calculateGrantableUris() { + protected void calculateGrantableUris() { final Notification notification = getNotification(); notification.visitUris((uri) -> { - visitGrantableUri(uri); + visitGrantableUri(uri, false); }); if (notification.getChannelId() != null) { NotificationChannel channel = getChannel(); if (channel != null) { - visitGrantableUri(channel.getSound()); + visitGrantableUri(channel.getSound(), (channel.getUserLockedFields() + & NotificationChannel.USER_LOCKED_SOUND) != 0); } } } @@ -1058,18 +1061,17 @@ public final class NotificationRecord { * {@link #mGrantableUris}. Otherwise, this will either log or throw * {@link SecurityException} depending on target SDK of enqueuing app. */ - private void visitGrantableUri(Uri uri) { + private void visitGrantableUri(Uri uri, boolean userOverriddenUri) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; // We can't grant Uri permissions from system final int sourceUid = sbn.getUid(); if (sourceUid == android.os.Process.SYSTEM_UID) return; - final IActivityManager am = ActivityManager.getService(); final long ident = Binder.clearCallingIdentity(); try { // This will throw SecurityException if caller can't grant - am.checkGrantUriPermission(sourceUid, null, + mAm.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); @@ -1081,10 +1083,12 @@ public final class NotificationRecord { } catch (RemoteException ignored) { // Ignored because we're in same process } catch (SecurityException e) { - if (mTargetSdkVersion >= Build.VERSION_CODES.P) { - throw e; - } else { - Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage()); + if (!userOverriddenUri) { + if (mTargetSdkVersion >= Build.VERSION_CODES.P) { + throw e; + } else { + Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage()); + } } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1b8c2cc8793e..9ed2b9c18546 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -14178,7 +14178,7 @@ public class PackageManagerService extends IPackageManager.Stub unactionedPackages.add(packageName); continue; } - if (!canSuspendPackageForUserLocked(packageName, userId)) { + if (suspended && !canSuspendPackageForUserLocked(packageName, userId)) { unactionedPackages.add(packageName); continue; } @@ -14333,44 +14333,44 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") private boolean canSuspendPackageForUserLocked(String packageName, int userId) { if (isPackageDeviceAdmin(packageName, userId)) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": has an active device admin"); return false; } String activeLauncherPackageName = getActiveLauncherPackageName(userId); if (packageName.equals(activeLauncherPackageName)) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": contains the active launcher"); return false; } if (packageName.equals(mRequiredInstallerPackage)) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for package installation"); return false; } if (packageName.equals(mRequiredUninstallerPackage)) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for package uninstallation"); return false; } if (packageName.equals(mRequiredVerifierPackage)) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for package verification"); return false; } if (packageName.equals(getDefaultDialerPackageName(userId))) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": is the default dialer"); return false; } if (mProtectedPackages.isPackageStateProtected(userId, packageName)) { - Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": protected package"); return false; } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index c9aa1ef1c007..1ae59cbea452 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -833,11 +833,11 @@ public final class DefaultPermissionGrantPolicy { getSystemPackage(textClassifierPackageName); if (textClassifierPackage != null && doesPackageSupportRuntimePermissions(textClassifierPackage)) { - grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId); - grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, true, userId); - grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, true, userId); - grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, true, userId); - grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, true, userId); + grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId); + grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId); + grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId); + grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId); + grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId); } } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index a02ee225861d..e11b64287fe3 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -157,6 +157,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004; /** Need to recompute animations */ int FINISH_LAYOUT_REDO_ANIM = 0x0008; + /** Layer for the screen off animation */ + int COLOR_FADE_LAYER = 0x40000001; /** * Register shortcuts for window manager to dispatch. diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 08d0ae9dcdd8..fa6079c51906 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; @@ -1377,7 +1378,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow"); // We can now show all of the drawn windows! - if (!mService.mOpeningApps.contains(this)) { + if (!mService.mOpeningApps.contains(this) && canShowWindows()) { showAllWindowsLocked(); } } @@ -2270,4 +2271,21 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree boolean isClosingOrEnteringPip() { return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip; } + + /** + * @return Whether we are allowed to show non-starting windows at the moment. We disallow + * showing windows during transitions in case we have windows that have wide-color-gamut + * color mode set to avoid jank in the middle of the transition. + */ + boolean canShowWindows() { + return allDrawn && !(isReallyAnimating() && hasNonDefaultColorWindow()); + } + + /** + * @return true if we have a window that has a non-default color mode set; false otherwise. + */ + private boolean hasNonDefaultColorWindow() { + return forAllWindows(ws -> ws.mAttrs.getColorMode() != COLOR_MODE_DEFAULT, + true /* topToBottom */); + } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b0e6208fdff3..47dbccb9a202 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -404,7 +404,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo WindowStateAnimator winAnimator = w.mWinAnimator; final AppWindowToken atoken = w.mAppToken; if (winAnimator.mDrawState == READY_TO_SHOW) { - if (atoken == null || atoken.allDrawn) { + if (atoken == null || atoken.canShowWindows()) { if (w.performShowLocked()) { pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; if (DEBUG_LAYOUT_REPEATS) { @@ -1106,11 +1106,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + forAllWindows(w -> { + w.forceSeamlesslyRotateIfAllowed(oldRotation, rotation); + }, true /* traverseTopToBottom */); + if (rotateSeamlessly) { - forAllWindows(w -> { - w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(), - oldRotation, rotation); - }, true /* traverseTopToBottom */); + seamlesslyRotate(getPendingTransaction(), oldRotation, rotation); } mService.mDisplayManagerInternal.performTraversal(getPendingTransaction()); @@ -3538,7 +3539,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // docked or freeform stack is visible...except for the home stack/task if the // docked stack is minimized and it actually set something. if (mHomeStack != null && mHomeStack.isVisible() - && mDividerControllerLocked.isMinimizedDock()) { + && mDividerControllerLocked.isMinimizedDock() + // TODO(b/110159357): Work around to unblock the release for failing test + // ActivityManagerAppConfigurationTests#testSplitscreenPortraitAppOrientationRequests + // which shouldn't be failing since home stack shouldn't be visible. We need + // to dig deeper to see why it is failing. NOTE: Not failing on current + // master... + && !(mDividerControllerLocked.isHomeStackResizable() + && mHomeStack.matchParentBounds())) { final int orientation = mHomeStack.getOrientation(); if (orientation != SCREEN_ORIENTATION_UNSET) { return orientation; @@ -3694,6 +3702,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } @Override + SurfaceControl.Builder makeChildSurface(WindowContainer child) { + final SurfaceControl.Builder builder = super.makeChildSurface(child); + if (child instanceof WindowToken && ((WindowToken) child).mRoundedCornerOverlay) { + // To draw above the ColorFade layer during the screen off transition, the + // rounded corner overlays need to be at the root of the surface hierarchy. + // TODO: move the ColorLayer into the display overlay layer such that this is not + // necessary anymore. + builder.setParent(null); + } + return builder; + } + + @Override void assignChildLayers(SurfaceControl.Transaction t) { assignChildLayers(t, null /* imeContainer */); } @@ -3709,6 +3730,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1); continue; } + if (wt.mRoundedCornerOverlay) { + wt.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); + continue; + } wt.assignLayer(t, j); wt.assignChildLayers(t); diff --git a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java new file mode 100644 index 000000000000..3218e83ecc20 --- /dev/null +++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; + +import android.graphics.Matrix; +import android.view.DisplayInfo; + +import com.android.server.wm.utils.CoordinateTransforms; + +/** + * Helper class for forced seamless rotation. + * + * Works by transforming the window token back into the old display rotation. + * + * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180 + * degree rotations. + */ +public class ForcedSeamlessRotator { + + private final Matrix mTransform = new Matrix(); + private final float[] mFloat9 = new float[9]; + + public ForcedSeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) { + final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270; + final int h = flipped ? info.logicalWidth : info.logicalHeight; + final int w = flipped ? info.logicalHeight : info.logicalWidth; + + final Matrix tmp = new Matrix(); + CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, w, h, mTransform); + CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); + mTransform.postConcat(tmp); + } + + /** + * Applies a transform to the window token's surface that undoes the effect of the global + * display rotation. + */ + public void unrotate(WindowToken token) { + token.getPendingTransaction().setMatrix(token.getSurfaceControl(), mTransform, mFloat9); + } + + /** + * Removes the transform to the window token's surface that undoes the effect of the global + * display rotation. + * + * Removing the transform and the result of the WindowState's layout are both tied to the + * WindowState's next frame, such that they apply at the same time the client draws the + * window in the new orientation. + */ + public void finish(WindowToken token, WindowState win) { + mTransform.reset(); + token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9); + token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl, + win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), + win.getFrameNumber()); + win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl, + win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), + win.getFrameNumber()); + } +} diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 19c5a3d6452a..8fe7063c815b 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -736,6 +736,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** + * Seamlessly rotates the container, by recomputing the location in the new + * rotation, and rotating buffers until they are updated for the new rotation. + * + * @param t the transaction to perform the seamless rotation in + * @param oldRotation the rotation we are rotating from + * @param newRotation the rotation we are rotating to + */ + void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + mChildren.get(i).seamlesslyRotate(t, oldRotation, newRotation); + } + } + + /** * Returns true if this container is opaque and fills all the space made available by its parent * container. * diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7a2c28bd5c82..ef745869b277 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1883,6 +1883,12 @@ public class WindowManagerService extends IWindowManager.Stub } win.setFrameNumber(frameNumber); + + if (win.mPendingForcedSeamlessRotate != null && !mWaitingForConfig) { + win.mPendingForcedSeamlessRotate.finish(win.mToken, win); + win.mPendingForcedSeamlessRotate = null; + } + int attrChanges = 0; int flagChanges = 0; if (attrs != null) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index bee70a011945..a7f432db8456 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -150,6 +150,8 @@ import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY; import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME; import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS; import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER; +import static com.android.server.wm.utils.CoordinateTransforms.transformRect; +import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import android.annotation.CallSuper; import android.app.AppOpsManager; @@ -278,6 +280,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private boolean mDragResizing; private boolean mDragResizingChangeReported = true; private int mResizeMode; + /** + * Special mode that is intended only for the rounded corner overlay: during rotation + * transition, we un-rotate the window token such that the window appears as it did before the + * rotation. + */ + final boolean mForceSeamlesslyRotate; + ForcedSeamlessRotator mPendingForcedSeamlessRotate; private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks; @@ -667,6 +676,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f; + void forceSeamlesslyRotateIfAllowed(int oldRotation, int rotation) { + if (mForceSeamlesslyRotate) { + mPendingForcedSeamlessRotate = new ForcedSeamlessRotator( + oldRotation, rotation, getDisplayInfo()); + mPendingForcedSeamlessRotate.unrotate(this.mToken); + } + } + interface PowerManagerWrapper { void wakeUp(long time, String reason); @@ -713,6 +730,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mSeq = seq; mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0; mPowerManagerWrapper = powerManagerWrapper; + mForceSeamlesslyRotate = token.mRoundedCornerOverlay; if (localLOGV) Slog.v( TAG, "Window " + this + " client=" + c.asBinder() + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a); @@ -1811,7 +1829,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0 && !isDragResizing() && !adjustedForMinimizedDockOrIme && getWindowConfiguration().hasMovementAnimations() - && !mWinAnimator.mLastHidden) { + && !mWinAnimator.mLastHidden + && !mSeamlesslyRotated) { startMoveAnimation(left, top); } @@ -4697,7 +4716,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition); - if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) { + // Freeze position while we're unrotated, so the surface remains at the position it was + // prior to the rotation. + if (!mSurfaceAnimator.hasLeash() && mPendingForcedSeamlessRotate == null && + !mLastSurfacePosition.equals(mSurfacePosition)) { t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y); mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y); if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) { @@ -4850,6 +4872,31 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mFrameNumber = frameNumber; } + @Override + void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) { + // Invisible windows, the wallpaper, and force seamlessly rotated windows do not participate + // in the regular seamless rotation animation. + if (!isVisibleNow() || mIsWallpaper || mForceSeamlesslyRotate) { + return; + } + final Matrix transform = mTmpMatrix; + + mService.markForSeamlessRotation(this, true); + + // We rotated the screen, but have not performed a new layout pass yet. In the mean time, + // we recompute the coordinates of mFrame in the new orientation, so the surface can be + // properly placed. + transformToRotation(oldRotation, newRotation, getDisplayInfo(), transform); + transformRect(transform, mFrame, null /* tmpRectF */); + + updateSurfacePosition(t); + mWinAnimator.seamlesslyRotate(t, oldRotation, newRotation); + + // Dispatch to children only after mFrame has been updated, as it's needed in the + // child's updateSurfacePosition. + super.seamlesslyRotate(t, oldRotation, newRotation); + } + private final class MoveAnimationSpec implements AnimationSpec { private final long mDuration; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 3eef12540e7f..a05e04dd6c7c 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -41,18 +41,18 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; import static com.android.server.wm.WindowManagerService.logWithStack; -import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE; import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT; import static com.android.server.wm.WindowStateAnimatorProto.SURFACE; import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT; +import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; +import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import android.content.Context; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.Region; import android.os.Debug; import android.os.Trace; @@ -366,7 +366,8 @@ class WindowStateAnimator { mDrawState = READY_TO_SHOW; boolean result = false; final AppWindowToken atoken = mWin.mAppToken; - if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) { + if (atoken == null || atoken.canShowWindows() + || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) { result = mWin.performShowLocked(); } return result; @@ -685,8 +686,11 @@ class WindowStateAnimator { final int displayId = mWin.getDisplayId(); final ScreenRotationAnimation screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(displayId); - final boolean screenAnimation = - screenRotationAnimation != null && screenRotationAnimation.isAnimating(); + final boolean windowParticipatesInScreenRotationAnimation = + !mWin.mForceSeamlesslyRotate; + final boolean screenAnimation = screenRotationAnimation != null + && screenRotationAnimation.isAnimating() + && windowParticipatesInScreenRotationAnimation; if (screenAnimation) { // cache often used attributes locally @@ -798,6 +802,13 @@ class WindowStateAnimator { return false; } + // During forced seamless rotation, the surface bounds get updated with the crop in the + // new rotation, which is not compatible with showing the surface in the old rotation. + // To work around that we disable cropping for such windows, as it is not necessary anyways. + if (w.mForceSeamlesslyRotate) { + return false; + } + // If we're animating, the wallpaper should only // be updated at the end of the animation. if (w.mAttrs.type == TYPE_WALLPAPER) { @@ -1492,40 +1503,14 @@ class WindowStateAnimator { } } - void seamlesslyRotateWindow(SurfaceControl.Transaction t, - int oldRotation, int newRotation) { + void seamlesslyRotate(SurfaceControl.Transaction t, int oldRotation, int newRotation) { final WindowState w = mWin; - if (!w.isVisibleNow() || w.mIsWallpaper) { - return; - } - final Rect cropRect = mService.mTmpRect; - final Rect displayRect = mService.mTmpRect2; - final RectF frameRect = mService.mTmpRectF; + // We rotated the screen, but have not received a new buffer with the correct size yet. In + // the mean time, we rotate the buffer we have to the new orientation. final Matrix transform = mService.mTmpTransform; - - final float x = w.mFrame.left; - final float y = w.mFrame.top; - final float width = w.mFrame.width(); - final float height = w.mFrame.height(); - - mService.getDefaultDisplayContentLocked().getBounds(displayRect); - final float displayWidth = displayRect.width(); - final float displayHeight = displayRect.height(); - - // Compute a transform matrix to undo the coordinate space transformation, - // and present the window at the same physical position it previously occupied. - final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation); - DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight, + transformToRotation(oldRotation, newRotation, w.mFrame.width(), w.mFrame.height(), transform); - - // We just need to apply a rotation matrix to the window. For example - // if we have a portrait window and rotate to landscape, the window is still portrait - // and now extends off the bottom of the screen (and only halfway across). Essentially we - // apply a transform to display the current buffer at it's old position - // (in the new coordinate space). We then freeze layer updates until the resize - // occurs, at which point we undo, them. - mService.markForSeamlessRotation(w, true); transform.getValues(mService.mTmpFloats); float DsDx = mService.mTmpFloats[Matrix.MSCALE_X]; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index b97460ae9eb8..e411c0adc75f 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -270,12 +270,6 @@ class WindowToken extends WindowContainer<WindowState> { dc.reParentWindowToken(this); mDisplayContent = dc; - // The rounded corner overlay should not be rotated. We ensure that by moving it outside - // the windowing layer. - if (mRoundedCornerOverlay) { - mDisplayContent.reparentToOverlay(mPendingTransaction, mSurfaceControl); - } - // TODO(b/36740756): One day this should perhaps be hooked // up with goodToGo, so we don't move a window // to another display before the window behind diff --git a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java index 09d7b5de1caf..a2f37a56598d 100644 --- a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java +++ b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java @@ -22,7 +22,11 @@ import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.annotation.Dimension; +import android.annotation.Nullable; import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.DisplayInfo; import android.view.Surface.Rotation; public class CoordinateTransforms { @@ -59,4 +63,93 @@ public class CoordinateTransforms { throw new IllegalArgumentException("Unknown rotation: " + rotation); } } + + /** + * Sets a matrix such that given a rotation, it transforms that rotation's logical coordinates + * to physical coordinates. + * + * @param rotation the rotation to which the matrix should transform + * @param out the matrix to be set + */ + public static void transformLogicalToPhysicalCoordinates(@Rotation int rotation, + @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) { + switch (rotation) { + case ROTATION_0: + out.reset(); + break; + case ROTATION_90: + out.setRotate(90); + out.preTranslate(0, -physicalWidth); + break; + case ROTATION_180: + out.setRotate(180); + out.preTranslate(-physicalWidth, -physicalHeight); + break; + case ROTATION_270: + out.setRotate(270); + out.preTranslate(-physicalHeight, 0); + break; + default: + throw new IllegalArgumentException("Unknown rotation: " + rotation); + } + } + + /** + * Sets a matrix such that given a two rotations, that it transforms coordinates given in the + * old rotation to coordinates that refer to the same physical location in the new rotation. + * + * @param oldRotation the rotation to transform from + * @param newRotation the rotation to transform to + * @param info the display info + * @param out a matrix that will be set to the transform + */ + public static void transformToRotation(@Rotation int oldRotation, + @Rotation int newRotation, DisplayInfo info, Matrix out) { + final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270; + final int h = flipped ? info.logicalWidth : info.logicalHeight; + final int w = flipped ? info.logicalHeight : info.logicalWidth; + + final Matrix tmp = new Matrix(); + transformLogicalToPhysicalCoordinates(oldRotation, w, h, out); + transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); + out.postConcat(tmp); + } + + /** + * Sets a matrix such that given a two rotations, that it transforms coordinates given in the + * old rotation to coordinates that refer to the same physical location in the new rotation. + * + * @param oldRotation the rotation to transform from + * @param newRotation the rotation to transform to + * @param newWidth the width of the area to transform, in the new rotation + * @param newHeight the height of the area to transform, in the new rotation + * @param out a matrix that will be set to the transform + */ + public static void transformToRotation(@Rotation int oldRotation, + @Rotation int newRotation, int newWidth, int newHeight, Matrix out) { + final boolean flipped = newRotation == ROTATION_90 || newRotation == ROTATION_270; + final int h = flipped ? newWidth : newHeight; + final int w = flipped ? newHeight : newWidth; + + final Matrix tmp = new Matrix(); + transformLogicalToPhysicalCoordinates(oldRotation, w, h, out); + transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp); + out.postConcat(tmp); + } + + /** + * Transforms a rect using a transformation matrix + * + * @param transform the transformation to apply to the rect + * @param inOutRect the rect to transform + * @param tmp a temporary value, if null the function will allocate its own. + */ + public static void transformRect(Matrix transform, Rect inOutRect, @Nullable RectF tmp) { + if (tmp == null) { + tmp = new RectF(); + } + tmp.set(inOutRect); + transform.mapRect(tmp); + inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java index 85e846db60b7..9f113ad3137e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import android.graphics.Rect; +import android.view.SurfaceControl; import android.view.WindowManager; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,6 +31,8 @@ import java.util.LinkedList; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90; +import static android.view.Surface.ROTATION_0; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -48,8 +52,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; @@ -349,6 +355,32 @@ public class WindowStateTests extends WindowTestsBase { assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId())); } + @Test + public void testSeamlesslyRotateWindow() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); + + app.mHasSurface = true; + app.mSurfaceControl = mock(SurfaceControl.class); + app.mWinAnimator.mSurfaceController = mock(WindowSurfaceController.class); + try { + app.mFrame.set(10, 20, 60, 80); + + app.seamlesslyRotate(t, ROTATION_0, ROTATION_90); + + assertTrue(app.mSeamlesslyRotated); + assertEquals(new Rect(20, mDisplayInfo.logicalWidth - 60, + 80, mDisplayInfo.logicalWidth - 10), app.mFrame); + + verify(t).setPosition(app.mSurfaceControl, app.mFrame.left, app.mFrame.top); + verify(app.mWinAnimator.mSurfaceController).setPosition(t, 0, 50, false); + verify(app.mWinAnimator.mSurfaceController).setMatrix(t, 0, -1, 1, 0, false); + } finally { + app.mSurfaceControl = null; + app.mHasSurface = false; + } + } + private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) { reset(mPowerManagerWrapper); final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java index 40a10e04c893..f82b01224f96 100644 --- a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java @@ -21,14 +21,19 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; +import static com.android.server.wm.utils.CoordinateTransforms.transformLogicalToPhysicalCoordinates; import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; + +import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; + import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; +import android.view.DisplayInfo; import org.junit.Before; import org.junit.Rule; @@ -41,6 +46,7 @@ public class CoordinateTransformsTest { private static final int H = 400; private final Matrix mMatrix = new Matrix(); + private final Matrix mMatrix2 = new Matrix(); @Rule public final ErrorCollector mErrorCollector = new ErrorCollector(); @@ -48,39 +54,140 @@ public class CoordinateTransformsTest { @Before public void setUp() throws Exception { mMatrix.setTranslate(0xdeadbeef, 0xdeadbeef); + mMatrix2.setTranslate(0xbeefdead, 0xbeefdead); } @Test - public void transformPhysicalToLogicalCoordinates_rot0() throws Exception { + public void transformPhysicalToLogicalCoordinates_rot0() { transformPhysicalToLogicalCoordinates(ROTATION_0, W, H, mMatrix); assertThat(mMatrix, is(Matrix.IDENTITY_MATRIX)); } @Test - public void transformPhysicalToLogicalCoordinates_rot90() throws Exception { + public void transformPhysicalToLogicalCoordinates_rot90() { transformPhysicalToLogicalCoordinates(ROTATION_90, W, H, mMatrix); - checkDevicePoint(0, 0).mapsToLogicalPoint(0, W); - checkDevicePoint(W, H).mapsToLogicalPoint(H, 0); + checkPoint(0, 0).transformsTo(0, W); + checkPoint(W, H).transformsTo(H, 0); } @Test - public void transformPhysicalToLogicalCoordinates_rot180() throws Exception { + public void transformPhysicalToLogicalCoordinates_rot180() { transformPhysicalToLogicalCoordinates(ROTATION_180, W, H, mMatrix); - checkDevicePoint(0, 0).mapsToLogicalPoint(W, H); - checkDevicePoint(W, H).mapsToLogicalPoint(0, 0); + checkPoint(0, 0).transformsTo(W, H); + checkPoint(W, H).transformsTo(0, 0); } @Test - public void transformPhysicalToLogicalCoordinates_rot270() throws Exception { + public void transformPhysicalToLogicalCoordinates_rot270() { transformPhysicalToLogicalCoordinates(ROTATION_270, W, H, mMatrix); - checkDevicePoint(0, 0).mapsToLogicalPoint(H, 0); - checkDevicePoint(W, H).mapsToLogicalPoint(0, W); + checkPoint(0, 0).transformsTo(H, 0); + checkPoint(W, H).transformsTo(0, W); + } + + @Test + public void transformLogicalToPhysicalCoordinates_rot0() { + transformLogicalToPhysicalCoordinates(ROTATION_0, W, H, mMatrix); + assertThat(mMatrix, is(Matrix.IDENTITY_MATRIX)); + } + + @Test + public void transformLogicalToPhysicalCoordinates_rot90() { + transformLogicalToPhysicalCoordinates(ROTATION_90, W, H, mMatrix); + + checkPoint(0, W).transformsTo(0, 0); + checkPoint(H, 0).transformsTo(W, H); + } + + @Test + public void transformLogicalToPhysicalCoordinates_rot180() { + transformLogicalToPhysicalCoordinates(ROTATION_180, W, H, mMatrix); + + checkPoint(W, H).transformsTo(0, 0); + checkPoint(0, 0).transformsTo(W, H); + } + + @Test + public void transformLogicalToPhysicalCoordinates_rot270() { + transformLogicalToPhysicalCoordinates(ROTATION_270, W, H, mMatrix); + + checkPoint(H, 0).transformsTo(0, 0); + checkPoint(0, W).transformsTo(W, H); + } + + @Test + public void transformLogicalToPhysicalCoordinatesIsInverse_rot0() { + transformLogicalToPhysicalCoordinates(ROTATION_0, W, H, mMatrix); + transformPhysicalToLogicalCoordinates(ROTATION_0, W, H, mMatrix2); + + assertMatricesAreInverses(mMatrix, mMatrix2); + } + + @Test + public void transformLogicalToPhysicalCoordinatesIsInverse_rot90() { + transformLogicalToPhysicalCoordinates(ROTATION_90, W, H, mMatrix); + transformPhysicalToLogicalCoordinates(ROTATION_90, W, H, mMatrix2); + + assertMatricesAreInverses(mMatrix, mMatrix2); + } + + @Test + public void transformLogicalToPhysicalCoordinatesIsInverse_rot180() { + transformLogicalToPhysicalCoordinates(ROTATION_180, W, H, mMatrix); + transformPhysicalToLogicalCoordinates(ROTATION_180, W, H, mMatrix2); + + assertMatricesAreInverses(mMatrix, mMatrix2); + } + + @Test + public void transformLogicalToPhysicalCoordinatesIsInverse_rot270() { + transformLogicalToPhysicalCoordinates(ROTATION_270, W, H, mMatrix); + transformPhysicalToLogicalCoordinates(ROTATION_270, W, H, mMatrix2); + + assertMatricesAreInverses(mMatrix, mMatrix2); + } + + @Test + public void transformBetweenRotations_rot180_rot270() { + // W,H are flipped, because they need to be given in the new orientation, i.e. ROT_270. + transformToRotation(ROTATION_180, ROTATION_270, H, W, mMatrix); + + checkPoint(0, 0).transformsTo(0, W); + checkPoint(W, H).transformsTo(H, 0); + } + + @Test + public void transformBetweenRotations_rot90_rot0() { + transformToRotation(ROTATION_180, ROTATION_270, W, H, mMatrix); + + checkPoint(0, 0).transformsTo(0, H); + // H,W is bottom right in ROT_90 + checkPoint(H, W).transformsTo(W, 0); + } + + @Test + public void transformBetweenRotations_displayInfo() { + final DisplayInfo di = new DisplayInfo(); + di.rotation = ROTATION_90; + di.logicalWidth = H; // dimensions are flipped in ROT_90 + di.logicalHeight = W; + transformToRotation(ROTATION_180, ROTATION_270, di, mMatrix); + + // W,H are flipped, because they need to be given in the new orientation, i.e. ROT_270. + transformToRotation(ROTATION_180, ROTATION_270, H, W, mMatrix2); + + assertEquals(mMatrix2, mMatrix); + } + + private void assertMatricesAreInverses(Matrix matrix, Matrix matrix2) { + final Matrix concat = new Matrix(); + concat.setConcat(matrix, matrix2); + assertTrue("expected identity, but was: " + concat, concat.isIdentity()); } - private DevicePointAssertable checkDevicePoint(int x, int y) { + private TransformPointAssertable checkPoint(int x, int y) { final Point devicePoint = new Point(x, y); final float[] fs = new float[] {x, y}; mMatrix.mapPoints(fs); @@ -92,7 +199,7 @@ public class CoordinateTransformsTest { }; } - public interface DevicePointAssertable { - void mapsToLogicalPoint(int x, int y); + public interface TransformPointAssertable { + void transformsTo(int x, int y); } }
\ No newline at end of file diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java index 345c1d7a95fe..eec852bd77c7 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java +++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java @@ -31,6 +31,7 @@ public class UiServiceTestCase { protected static final String PKG_N_MR1 = "com.example.n_mr1"; protected static final String PKG_O = "com.example.o"; + protected static final String PKG_P = "com.example.p"; @Rule public final TestableContext mContext = @@ -57,6 +58,8 @@ public class UiServiceTestCase { return Build.VERSION_CODES.N_MR1; case PKG_O: return Build.VERSION_CODES.O; + case PKG_P: + return Build.VERSION_CODES.P; default: return Build.VERSION_CODES.CUR_DEVELOPMENT; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index a408438b7633..cdbf3c66767b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2942,6 +2942,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testVisualDifference_summaryNewNotification() { + Notification.Builder nb2 = new Notification.Builder(mContext, "") + .setGroup("bananas") + .setFlag(Notification.FLAG_GROUP_SUMMARY, true) + .setContentText("bar"); + StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb2.build(), new UserHandle(mUid), null, 0); + NotificationRecord r2 = + new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); + + assertFalse(mService.isVisuallyInterruptive(null, r2)); + } + + @Test public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { // post 2 notification from this package final NotificationRecord notif1 = generateNotificationRecord( diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index c1868e7da921..e28699113a3d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -29,9 +29,17 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.app.IActivityManager; import android.app.Notification; import android.app.Notification.Builder; import android.app.NotificationChannel; @@ -44,12 +52,14 @@ import android.media.AudioAttributes; import android.metrics.LogMaker; import android.net.Uri; import android.os.Bundle; +import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.service.notification.Adjustment; import android.service.notification.StatusBarNotification; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Slog; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.UiServiceTestCase; @@ -58,7 +68,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.Objects; @@ -67,7 +76,7 @@ import java.util.Objects; @RunWith(AndroidJUnit4.class) public class NotificationRecordTest extends UiServiceTestCase { - private final Context mMockContext = Mockito.mock(Context.class); + private final Context mMockContext = mock(Context.class); @Mock PackageManager mPm; private final String pkg = PKG_N_MR1; @@ -93,8 +102,6 @@ public class NotificationRecordTest extends UiServiceTestCase { new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test", NotificationManager.IMPORTANCE_UNSPECIFIED); private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); - final ApplicationInfo legacy = new ApplicationInfo(); - final ApplicationInfo upgrade = new ApplicationInfo(); private static final long[] CUSTOM_VIBRATION = new long[] { 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, @@ -115,12 +122,12 @@ public class NotificationRecordTest extends UiServiceTestCase { when(mMockContext.getResources()).thenReturn(getContext().getResources()); when(mMockContext.getPackageManager()).thenReturn(mPm); + when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); } - private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound, + private StatusBarNotification getNotification(String pkg, boolean noisy, boolean defaultSound, boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights, String group) { - when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade); final Builder builder = new Builder(mMockContext) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) @@ -159,22 +166,14 @@ public class NotificationRecordTest extends UiServiceTestCase { } builder.setDefaults(defaults); - if (!preO) { - builder.setChannelId(channelId); - } + builder.setChannelId(channelId); if(group != null) { builder.setGroup(group); } Notification n = builder.build(); - if (preO) { - return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, - mUser, null, uid); - } else { - return new StatusBarNotification(pkg2, pkg2, id2, tag2, uid2, uid2, n, - mUser, null, uid2); - } + return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); } // @@ -185,7 +184,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testSound_default_preUpgradeUsesNotification() throws Exception { defaultChannel.setSound(null, null); // pre upgrade, default sound. - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -198,7 +197,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testSound_custom_preUpgradeUsesNotification() throws Exception { defaultChannel.setSound(null, null); // pre upgrade, custom sound. - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -212,7 +211,7 @@ public class NotificationRecordTest extends UiServiceTestCase { defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES); defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND); // pre upgrade, default sound. - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -224,7 +223,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testSound_noSound_preUpgrade() throws Exception { // pre upgrade, default sound. - StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */, false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -237,7 +236,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testSound_default_upgradeUsesChannel() throws Exception { channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES); // post upgrade, default sound. - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -250,7 +249,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testVibration_default_preUpgradeUsesNotification() throws Exception { defaultChannel.enableVibration(false); // pre upgrade, default vibration. - StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */, false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -262,7 +261,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testVibration_custom_preUpgradeUsesNotification() throws Exception { defaultChannel.enableVibration(false); // pre upgrade, custom vibration. - StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */, false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -275,7 +274,7 @@ public class NotificationRecordTest extends UiServiceTestCase { defaultChannel.enableVibration(true); defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION); // pre upgrade, custom vibration. - StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */, false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -287,7 +286,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testVibration_custom_upgradeUsesChannel() throws Exception { channel.enableVibration(true); // post upgrade, custom vibration. - StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */, false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -297,7 +296,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testImportance_preUpgrade() throws Exception { - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); @@ -308,7 +307,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testImportance_locked_preUpgrade() throws Exception { defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW); defaultChannel.lockFields(USER_LOCKED_IMPORTANCE); - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -320,7 +319,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testImportance_locked_unspecified_preUpgrade() throws Exception { defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED); defaultChannel.lockFields(USER_LOCKED_IMPORTANCE); - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); @@ -330,7 +329,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testImportance_upgrade() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -339,7 +338,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLights_preUpgrade_noLight() throws Exception { - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); @@ -349,7 +348,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLights_preUpgrade() throws Exception { - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, true /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); @@ -360,7 +359,7 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testLights_locked_preUpgrade() throws Exception { defaultChannel.enableLights(true); defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS); - StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, true /* lights */, false /* defaultLights */, null /* group */); @@ -379,7 +378,7 @@ public class NotificationRecordTest extends UiServiceTestCase { NotificationRecord.Light expected = new NotificationRecord.Light( defaultLightColor, defaultLightOn, defaultLightOff); - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, true /* lights */, true /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -395,7 +394,7 @@ public class NotificationRecordTest extends UiServiceTestCase { NotificationRecord.Light expected = new NotificationRecord.Light( Color.BLUE, defaultLightOn, defaultLightOff); - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, true /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -404,7 +403,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLights_upgrade_noLight() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); @@ -413,7 +412,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLogmakerShortChannel() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -426,7 +425,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLogmakerLongChannel() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /*defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channelLongId); @@ -437,7 +436,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLogmakerNoGroup() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /*defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -446,7 +445,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLogmakerShortGroup() throws Exception { - StatusBarNotification sbn = getNotification(false /*reO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -456,7 +455,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLogmakerLongGroup() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupIdLong /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -467,7 +466,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testLogmakerOverrideGroup() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -483,7 +482,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testNotificationStats() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -526,7 +525,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testUserSentiment() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -544,7 +543,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testUserSentiment_appImportanceUpdatesSentiment() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -556,7 +555,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testUserSentiment_appImportanceBlocksNegativeSentimentUpdate() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -573,7 +572,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testUserSentiment_userLocked() throws Exception { channel.lockFields(USER_LOCKED_IMPORTANCE); - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -591,7 +590,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testAppImportance_returnsCorrectly() throws Exception { - StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, groupId /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -605,7 +604,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testIsInterruptive_textChanged_notSeen() { - StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */, false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -618,7 +617,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testIsInterruptive_textChanged_seen() { - StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */, false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -632,7 +631,7 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testIsInterruptive_textNotChanged_seen() { - StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */, + StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */, false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, false /* lights */, false /* defaultLights */, null /* group */); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); @@ -643,4 +642,59 @@ public class NotificationRecordTest extends UiServiceTestCase { record.setSeen(); assertEquals(false, record.isInterruptive()); } + + @Test + public void testCalculateGrantableUris_PappProvided() throws RemoteException { + IActivityManager am = mock(IActivityManager.class); + when(am.checkGrantUriPermission(anyInt(), eq(null), any(), + anyInt(), anyInt())).thenThrow(new SecurityException()); + + Notification n = mock(Notification.class); + when(n.getChannelId()).thenReturn(channel.getId()); + StatusBarNotification sbn = + new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.mAm = am; + + try { + record.calculateGrantableUris(); + fail("App provided uri for p targeting app should throw exception"); + } catch (SecurityException e) { + // expected + } + } + + @Test + public void testCalculateGrantableUris_PuserOverridden() throws RemoteException { + IActivityManager am = mock(IActivityManager.class); + when(am.checkGrantUriPermission(anyInt(), eq(null), any(), + anyInt(), anyInt())).thenThrow(SecurityException.class); + + channel.lockFields(NotificationChannel.USER_LOCKED_SOUND); + Notification n = mock(Notification.class); + when(n.getChannelId()).thenReturn(channel.getId()); + StatusBarNotification sbn = + new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.mAm = am; + + record.calculateGrantableUris(); + } + + @Test + public void testCalculateGrantableUris_prePappProvided() throws RemoteException { + IActivityManager am = mock(IActivityManager.class); + when(am.checkGrantUriPermission(anyInt(), eq(null), any(), + anyInt(), anyInt())).thenThrow(SecurityException.class); + + Notification n = mock(Notification.class); + when(n.getChannelId()).thenReturn(channel.getId()); + StatusBarNotification sbn = + new StatusBarNotification(PKG_O, PKG_O, id1, tag1, uid, uid, n, mUser, null, uid); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.mAm = am; + + record.calculateGrantableUris(); + // should not throw + } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 4d5dff40ba36..e7dfe6314fdd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -335,11 +335,18 @@ public class TelephonyManager { * <p> * The {@link #EXTRA_STATE} extra indicates the new call state. * If a receiving app has {@link android.Manifest.permission#READ_CALL_LOG} permission, a second - * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outoing calls - * as a String. Note: If the receiving app has + * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outgoing + * calls as a String. + * <p> + * If the receiving app has * {@link android.Manifest.permission#READ_CALL_LOG} and * {@link android.Manifest.permission#READ_PHONE_STATE} permission, it will receive the - * broadcast twice; one with the phone number and another without it. + * broadcast twice; one with the {@link #EXTRA_INCOMING_NUMBER} populated with the phone number, + * and another with it blank. Due to the nature of broadcasts, you cannot assume the order + * in which these broadcasts will arrive, however you are guaranteed to receive two in this + * case. Apps which are interested in the {@link #EXTRA_INCOMING_NUMBER} can ignore the + * broadcasts where {@link #EXTRA_INCOMING_NUMBER} is not present in the extras (e.g. where + * {@link Intent#hasExtra(String)} returns {@code false}). * <p class="note"> * This was a {@link android.content.Context#sendStickyBroadcast sticky} * broadcast in version 1.0, but it is no longer sticky. @@ -488,10 +495,19 @@ public class TelephonyManager { public static final String EXTRA_STATE_OFFHOOK = PhoneConstants.State.OFFHOOK.toString(); /** - * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast - * for a String containing the incoming phone number. - * Only valid when the new call state is RINGING. - * + * Extra key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast + * for a String containing the incoming or outgoing phone number. + * <p> + * This extra is only populated for receivers of the {@link #ACTION_PHONE_STATE_CHANGED} + * broadcast which have been granted the {@link android.Manifest.permission#READ_CALL_LOG} and + * {@link android.Manifest.permission#READ_PHONE_STATE} permissions. + * <p> + * For incoming calls, the phone number is only guaranteed to be populated when the + * {@link #EXTRA_STATE} changes from {@link #EXTRA_STATE_IDLE} to {@link #EXTRA_STATE_RINGING}. + * If the incoming caller is from an unknown number, the extra will be populated with an empty + * string. + * For outgoing calls, the phone number is only guaranteed to be populated when the + * {@link #EXTRA_STATE} changes from {@link #EXTRA_STATE_IDLE} to {@link #EXTRA_STATE_OFFHOOK}. * <p class="note"> * Retrieve with * {@link android.content.Intent#getStringExtra(String)}. @@ -5463,23 +5479,6 @@ public class TelephonyManager { } /** - * @return true if the IMS resolver is busy resolving a binding and should not be considered - * available, false if the IMS resolver is idle. - * @hide - */ - public boolean isResolvingImsBinding() { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - return telephony.isResolvingImsBinding(); - } - } catch (RemoteException e) { - Rlog.e(TAG, "isResolvingImsBinding, RemoteException: " + e.getMessage()); - } - return false; - } - - /** * Set IMS registration state * * @param Registration state diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index a2b85807ffa0..f875a9868198 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -31,6 +31,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; @@ -628,33 +629,33 @@ public class ApnSetting implements Parcelable { int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType, String mvnoMatchData, int apnSetId) { return new Builder() - .setId(id) - .setOperatorNumeric(operatorNumeric) - .setEntryName(entryName) - .setApnName(apnName) - .setProxyAddress(proxyAddress) - .setProxyPort(proxyPort) - .setMmsc(mmsc) - .setMmsProxyAddress(mmsProxyAddress) - .setMmsProxyPort(mmsProxyPort) - .setUser(user) - .setPassword(password) - .setAuthType(authType) - .setApnTypeBitmask(mApnTypeBitmask) - .setProtocol(protocol) - .setRoamingProtocol(roamingProtocol) - .setCarrierEnabled(carrierEnabled) - .setNetworkTypeBitmask(networkTypeBitmask) - .setProfileId(profileId) - .setModemCognitive(modemCognitive) - .setMaxConns(maxConns) - .setWaitTime(waitTime) - .setMaxConnsTime(maxConnsTime) - .setMtu(mtu) - .setMvnoType(mvnoType) - .setMvnoMatchData(mvnoMatchData) - .setApnSetId(apnSetId) - .buildWithoutCheck(); + .setId(id) + .setOperatorNumeric(operatorNumeric) + .setEntryName(entryName) + .setApnName(apnName) + .setProxyAddress(proxyAddress) + .setProxyPort(proxyPort) + .setMmsc(mmsc) + .setMmsProxyAddress(mmsProxyAddress) + .setMmsProxyPort(mmsProxyPort) + .setUser(user) + .setPassword(password) + .setAuthType(authType) + .setApnTypeBitmask(mApnTypeBitmask) + .setProtocol(protocol) + .setRoamingProtocol(roamingProtocol) + .setCarrierEnabled(carrierEnabled) + .setNetworkTypeBitmask(networkTypeBitmask) + .setProfileId(profileId) + .setModemCognitive(modemCognitive) + .setMaxConns(maxConns) + .setWaitTime(waitTime) + .setMaxConnsTime(maxConnsTime) + .setMtu(mtu) + .setMvnoType(mvnoType) + .setMvnoMatchData(mvnoMatchData) + .setApnSetId(apnSetId) + .buildWithoutCheck(); } /** @hide */ @@ -686,56 +687,56 @@ public class ApnSetting implements Parcelable { } return makeApnSetting( - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), - UriFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), - apnTypesBitmask, - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))), - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.ROAMING_PROTOCOL))), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.CARRIER_ENABLED)) == 1, - networkTypeBitmask, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MODEM_COGNITIVE)) == 1, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MAX_CONNS_TIME)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), - getMvnoTypeIntFromString( + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), + portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), + UriFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), + portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), + apnTypesBitmask, + getProtocolIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))), + getProtocolIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL))), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.CARRIER_ENABLED)) == 1, + networkTypeBitmask, + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MODEM_COGNITIVE)) == 1, + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MAX_CONNS_TIME)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), + getMvnoTypeIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE))), cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_TYPE))), - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_MATCH_DATA)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID))); + Telephony.Carriers.MVNO_MATCH_DATA)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID))); } /** @hide */ public static ApnSetting makeApnSetting(ApnSetting apn) { return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, - apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, - apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, - apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask, - apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, - apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId); + apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, + apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, + apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask, + apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, + apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId); } /** @@ -925,16 +926,16 @@ public class ApnSetting implements Parcelable { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[ApnSettingV5] ") - .append(mEntryName) - .append(", ").append(mId) - .append(", ").append(mOperatorNumeric) - .append(", ").append(mApnName) - .append(", ").append(mProxyAddress) - .append(", ").append(UriToString(mMmsc)) - .append(", ").append(mMmsProxyAddress) - .append(", ").append(portToString(mMmsProxyPort)) - .append(", ").append(portToString(mProxyPort)) - .append(", ").append(mAuthType).append(", "); + .append(mEntryName) + .append(", ").append(mId) + .append(", ").append(mOperatorNumeric) + .append(", ").append(mApnName) + .append(", ").append(mProxyAddress) + .append(", ").append(UriToString(mMmsc)) + .append(", ").append(mMmsProxyAddress) + .append(", ").append(portToString(mMmsProxyPort)) + .append(", ").append(portToString(mProxyPort)) + .append(", ").append(mAuthType).append(", "); final String[] types = getApnTypesStringFromBitmask(mApnTypeBitmask).split(","); sb.append(TextUtils.join(" | ", types)); sb.append(", ").append(PROTOCOL_INT_MAP.get(mProtocol)); @@ -1016,31 +1017,31 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mId, other.mId) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && Objects.equals(mProtocol, other.mProtocol) - && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mModemCognitive, other.mModemCognitive) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) - && Objects.equals(mApnSetId, other.mApnSetId); + && Objects.equals(mId, other.mId) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort,other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && Objects.equals(mProtocol, other.mProtocol) + && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mModemCognitive, other.mModemCognitive) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtu, other.mMtu) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) + && Objects.equals(mApnSetId, other.mApnSetId); } /** @@ -1063,29 +1064,29 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) - && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mModemCognitive, other.mModemCognitive) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mApnSetId, other.mApnSetId); + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol)) + && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mModemCognitive, other.mModemCognitive) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtu, other.mMtu) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mApnSetId, other.mApnSetId); } /** @@ -1097,22 +1098,22 @@ public class ApnSetting implements Parcelable { */ public boolean similar(ApnSetting other) { return (!this.canHandleType(TYPE_DUN) - && !other.canHandleType(TYPE_DUN) - && Objects.equals(this.mApnName, other.mApnName) - && !typeSameAny(this, other) - && xorEquals(this.mProxyAddress, other.mProxyAddress) - && xorEqualsInt(this.mProxyPort, other.mProxyPort) - && xorEquals(this.mProtocol, other.mProtocol) - && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol) - && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(this.mProfileId, other.mProfileId) - && Objects.equals(this.mMvnoType, other.mMvnoType) - && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData) - && xorEquals(this.mMmsc, other.mMmsc) - && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress) - && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort)) - && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask) - && Objects.equals(mApnSetId, other.mApnSetId); + && !other.canHandleType(TYPE_DUN) + && Objects.equals(this.mApnName, other.mApnName) + && !typeSameAny(this, other) + && xorEquals(this.mProxyAddress, other.mProxyAddress) + && xorEqualsInt(this.mProxyPort, other.mProxyPort) + && xorEquals(this.mProtocol, other.mProtocol) + && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(this.mProfileId, other.mProfileId) + && Objects.equals(this.mMvnoType, other.mMvnoType) + && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData) + && xorEquals(this.mMmsc, other.mMmsc) + && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress) + && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort)) + && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask) + && Objects.equals(mApnSetId, other.mApnSetId); } // Equal or one is null. @@ -1336,13 +1337,13 @@ public class ApnSetting implements Parcelable { new Parcelable.Creator<ApnSetting>() { @Override public ApnSetting createFromParcel(Parcel in) { - return readFromParcel(in); - } + return readFromParcel(in); + } @Override public ApnSetting[] newArray(int size) { - return new ApnSetting[size]; - } + return new ApnSetting[size]; + } }; /** diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index f02f27d1699c..89a4caad4d30 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -817,12 +817,6 @@ interface ITelephony { IImsConfig getImsConfig(int slotId, int feature); /** - * @return true if the IMS resolver is busy resolving a binding and should not be considered - * available, false if the IMS resolver is idle. - */ - boolean isResolvingImsBinding(); - - /** * @return true if the ImsService to bind to for the slot id specified was set, false otherwise. */ boolean setImsService(int slotId, boolean isCarrierImsService, String packageName); diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 34ecde8027c7..0d3b8e4a0452 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -71,6 +71,7 @@ import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; @@ -128,6 +129,10 @@ public class TetheringTest { private static final String TEST_USB_IFNAME = "test_rndis0"; private static final String TEST_WLAN_IFNAME = "test_wlan0"; + // Actual contents of the request don't matter for this test. The lack of + // any specific TRANSPORT_* is sufficient to identify this request. + private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build(); + @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private INetworkManagementService mNMService; @@ -238,6 +243,11 @@ public class TetheringTest { isTetheringSupportedCalls++; return true; } + + @Override + public NetworkRequest getDefaultNetworkRequest() { + return mDefaultRequest; + } } private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6, @@ -305,6 +315,8 @@ public class TetheringTest { .thenReturn(new String[0]); when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); + when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) + .thenReturn(false); when(mNMService.listInterfaces()) .thenReturn(new String[] { TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME}); @@ -458,6 +470,7 @@ public class TetheringTest { } private void prepareUsbTethering(NetworkState upstreamState) { + when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) .thenReturn(upstreamState); @@ -519,7 +532,7 @@ public class TetheringTest { TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); - verify(mUpstreamNetworkMonitor, times(1)).start(); + verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class)); // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast(). assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls); @@ -656,6 +669,24 @@ public class TetheringTest { } @Test + public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception { + when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) + .thenReturn(true); + sendConfigurationChanged(); + + // Setup IPv6 + final NetworkState upstreamState = buildMobileIPv6UpstreamState(); + runUsbTethering(upstreamState); + + // UpstreamNetworkMonitor should choose upstream automatically + // (in this specific case: choose the default network). + verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream(); + verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any()); + + verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network); + } + + @Test public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception { workingLocalOnlyHotspotEnrichedApBroadcast(true); } @@ -718,7 +749,7 @@ public class TetheringTest { TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER); - verify(mUpstreamNetworkMonitor, times(1)).start(); + verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class)); // In tethering mode, in the default configuration, an explicit request // for a mobile network is also made. verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest(); diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java index 9661dc24ca2e..3e21a2cfb7f9 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -73,6 +74,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; @@ -84,6 +86,10 @@ public class UpstreamNetworkMonitorTest { private static final boolean INCLUDES = true; private static final boolean EXCLUDES = false; + // Actual contents of the request don't matter for this test. The lack of + // any specific TRANSPORT_* is sufficient to identify this request. + private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build(); + @Mock private Context mContext; @Mock private IConnectivityManager mCS; @Mock private SharedLog mLog; @@ -113,6 +119,13 @@ public class UpstreamNetworkMonitorTest { } @Test + public void testStopWithoutStartIsNonFatal() { + mUNM.stop(); + mUNM.stop(); + mUNM.stop(); + } + + @Test public void testDoesNothingBeforeStarted() { assertTrue(mCM.hasNoCallbacks()); assertFalse(mUNM.mobileNetworkRequested()); @@ -127,7 +140,7 @@ public class UpstreamNetworkMonitorTest { public void testDefaultNetworkIsTracked() throws Exception { assertEquals(0, mCM.trackingDefault.size()); - mUNM.start(); + mUNM.start(mDefaultRequest); assertEquals(1, mCM.trackingDefault.size()); mUNM.stop(); @@ -138,7 +151,7 @@ public class UpstreamNetworkMonitorTest { public void testListensForAllNetworks() throws Exception { assertTrue(mCM.listening.isEmpty()); - mUNM.start(); + mUNM.start(mDefaultRequest); assertFalse(mCM.listening.isEmpty()); assertTrue(mCM.isListeningForAll()); @@ -148,9 +161,11 @@ public class UpstreamNetworkMonitorTest { @Test public void testCallbacksRegistered() { - mUNM.start(); - verify(mCM, times(1)).registerNetworkCallback(any(), any(), any()); - verify(mCM, times(1)).registerDefaultNetworkCallback(any(), any()); + mUNM.start(mDefaultRequest); + verify(mCM, times(1)).registerNetworkCallback( + any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); + verify(mCM, times(1)).requestNetwork( + eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class)); mUNM.stop(); verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class)); @@ -161,7 +176,7 @@ public class UpstreamNetworkMonitorTest { assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); - mUNM.start(); + mUNM.start(mDefaultRequest); assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); @@ -184,17 +199,17 @@ public class UpstreamNetworkMonitorTest { assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); - mUNM.start(); - verify(mCM, Mockito.times(1)).registerNetworkCallback( + mUNM.start(mDefaultRequest); + verify(mCM, times(1)).registerNetworkCallback( any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); - verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback( - any(NetworkCallback.class), any(Handler.class)); + verify(mCM, times(1)).requestNetwork( + eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class)); assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); mUNM.updateMobileRequiresDun(true); mUNM.registerMobileNetworkRequest(); - verify(mCM, Mockito.times(1)).requestNetwork( + verify(mCM, times(1)).requestNetwork( any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(), any(Handler.class)); @@ -222,7 +237,7 @@ public class UpstreamNetworkMonitorTest { assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); - mUNM.start(); + mUNM.start(mDefaultRequest); assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); @@ -242,7 +257,7 @@ public class UpstreamNetworkMonitorTest { @Test public void testUpdateMobileRequiresDun() throws Exception { - mUNM.start(); + mUNM.start(mDefaultRequest); // Test going from no-DUN to DUN correctly re-registers callbacks. mUNM.updateMobileRequiresDun(false); @@ -270,7 +285,7 @@ public class UpstreamNetworkMonitorTest { final Collection<Integer> preferredTypes = new ArrayList<>(); preferredTypes.add(TYPE_WIFI); - mUNM.start(); + mUNM.start(mDefaultRequest); // There are no networks, so there is nothing to select. assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); @@ -334,8 +349,47 @@ public class UpstreamNetworkMonitorTest { } @Test + public void testGetCurrentPreferredUpstream() throws Exception { + mUNM.start(mDefaultRequest); + mUNM.updateMobileRequiresDun(false); + + // [0] Mobile connects, DUN not required -> mobile selected. + final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR); + cellAgent.fakeConnect(); + mCM.makeDefaultNetwork(cellAgent); + assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network); + + // [1] WiFi connects but not validated/promoted to default -> mobile selected. + final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI); + wifiAgent.fakeConnect(); + assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network); + + // [2] WiFi validates and is promoted to the default network -> WiFi selected. + mCM.makeDefaultNetwork(wifiAgent); + assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network); + + // [3] DUN required, no other changes -> WiFi still selected + mUNM.updateMobileRequiresDun(true); + assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network); + + // [4] WiFi no longer validated, mobile becomes default, DUN required -> null selected. + mCM.makeDefaultNetwork(cellAgent); + assertEquals(null, mUNM.getCurrentPreferredUpstream()); + // TODO: make sure that a DUN request has been filed. This is currently + // triggered by code over in Tethering, but once that has been moved + // into UNM we should test for this here. + + // [5] DUN network arrives -> DUN selected + final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR); + dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN); + dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET); + dunAgent.fakeConnect(); + assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network); + } + + @Test public void testLocalPrefixes() throws Exception { - mUNM.start(); + mUNM.start(mDefaultRequest); // [0] Test minimum set of local prefixes. Set<IpPrefix> local = mUNM.getLocalPrefixes(); @@ -345,7 +399,7 @@ public class UpstreamNetworkMonitorTest { // [1] Pretend Wi-Fi connects. final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI); - final LinkProperties wifiLp = new LinkProperties(); + final LinkProperties wifiLp = wifiAgent.linkProperties; wifiLp.setInterfaceName("wlan0"); final String[] WIFI_ADDRS = { "fe80::827a:bfff:fe6f:374d", "100.112.103.18", @@ -358,7 +412,7 @@ public class UpstreamNetworkMonitorTest { wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr)); } wifiAgent.fakeConnect(); - wifiAgent.sendLinkProperties(wifiLp); + wifiAgent.sendLinkProperties(); local = mUNM.getLocalPrefixes(); assertPrefixSet(local, INCLUDES, alreadySeen); @@ -372,7 +426,7 @@ public class UpstreamNetworkMonitorTest { // [2] Pretend mobile connects. final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR); - final LinkProperties cellLp = new LinkProperties(); + final LinkProperties cellLp = cellAgent.linkProperties; cellLp.setInterfaceName("rmnet_data0"); final String[] CELL_ADDRS = { "10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d", @@ -382,7 +436,7 @@ public class UpstreamNetworkMonitorTest { cellLp.addLinkAddress(new LinkAddress(addrStr + cidr)); } cellAgent.fakeConnect(); - cellAgent.sendLinkProperties(cellLp); + cellAgent.sendLinkProperties(); local = mUNM.getLocalPrefixes(); assertPrefixSet(local, INCLUDES, alreadySeen); @@ -394,17 +448,18 @@ public class UpstreamNetworkMonitorTest { // [3] Pretend DUN connects. final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR); dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN); - final LinkProperties dunLp = new LinkProperties(); + dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET); + final LinkProperties dunLp = dunAgent.linkProperties; dunLp.setInterfaceName("rmnet_data1"); final String[] DUN_ADDRS = { "192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d", }; for (String addrStr : DUN_ADDRS) { final String cidr = addrStr.contains(":") ? "/64" : "/27"; - cellLp.addLinkAddress(new LinkAddress(addrStr + cidr)); + dunLp.addLinkAddress(new LinkAddress(addrStr + cidr)); } dunAgent.fakeConnect(); - dunAgent.sendLinkProperties(dunLp); + dunAgent.sendLinkProperties(); local = mUNM.getLocalPrefixes(); assertPrefixSet(local, INCLUDES, alreadySeen); @@ -442,6 +497,7 @@ public class UpstreamNetworkMonitorTest { public static class TestConnectivityManager extends ConnectivityManager { public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>(); public Set<NetworkCallback> trackingDefault = new HashSet<>(); + public TestNetworkAgent defaultNetwork = null; public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>(); public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>(); public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>(); @@ -483,12 +539,34 @@ public class UpstreamNetworkMonitorTest { int getNetworkId() { return ++mNetworkId; } + void makeDefaultNetwork(TestNetworkAgent agent) { + if (Objects.equals(defaultNetwork, agent)) return; + + final TestNetworkAgent formerDefault = defaultNetwork; + defaultNetwork = agent; + + for (NetworkCallback cb : trackingDefault) { + if (defaultNetwork != null) { + cb.onAvailable(defaultNetwork.networkId); + cb.onCapabilitiesChanged( + defaultNetwork.networkId, defaultNetwork.networkCapabilities); + cb.onLinkPropertiesChanged( + defaultNetwork.networkId, defaultNetwork.linkProperties); + } + } + } + @Override public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) { assertFalse(allCallbacks.containsKey(cb)); allCallbacks.put(cb, h); - assertFalse(requested.containsKey(cb)); - requested.put(cb, req); + if (mDefaultRequest.equals(req)) { + assertFalse(trackingDefault.contains(cb)); + trackingDefault.add(cb); + } else { + assertFalse(requested.containsKey(cb)); + requested.put(cb, req); + } } @Override @@ -524,10 +602,7 @@ public class UpstreamNetworkMonitorTest { @Override public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) { - assertFalse(allCallbacks.containsKey(cb)); - allCallbacks.put(cb, h); - assertFalse(trackingDefault.contains(cb)); - trackingDefault.add(cb); + fail("Should never be called."); } @Override @@ -561,6 +636,7 @@ public class UpstreamNetworkMonitorTest { public final Network networkId; public final int transportType; public final NetworkCapabilities networkCapabilities; + public final LinkProperties linkProperties; public TestNetworkAgent(TestConnectivityManager cm, int transportType) { this.cm = cm; @@ -569,12 +645,14 @@ public class UpstreamNetworkMonitorTest { networkCapabilities = new NetworkCapabilities(); networkCapabilities.addTransportType(transportType); networkCapabilities.addCapability(NET_CAPABILITY_INTERNET); + linkProperties = new LinkProperties(); } public void fakeConnect() { for (NetworkCallback cb : cm.listening.keySet()) { cb.onAvailable(networkId); cb.onCapabilitiesChanged(networkId, copy(networkCapabilities)); + cb.onLinkPropertiesChanged(networkId, copy(linkProperties)); } } @@ -584,11 +662,16 @@ public class UpstreamNetworkMonitorTest { } } - public void sendLinkProperties(LinkProperties lp) { + public void sendLinkProperties() { for (NetworkCallback cb : cm.listening.keySet()) { - cb.onLinkPropertiesChanged(networkId, lp); + cb.onLinkPropertiesChanged(networkId, copy(linkProperties)); } } + + @Override + public String toString() { + return String.format("TestNetworkAgent: %s %s", networkId, networkCapabilities); + } } public static class TestStateMachine extends StateMachine { @@ -618,6 +701,10 @@ public class UpstreamNetworkMonitorTest { return new NetworkCapabilities(nc); } + static LinkProperties copy(LinkProperties lp) { + return new LinkProperties(lp); + } + static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected) { final Set<String> expectedSet = new HashSet<>(); Collections.addAll(expectedSet, expected); |