diff options
226 files changed, 4683 insertions, 4127 deletions
diff --git a/Android.bp b/Android.bp index e59daf13b7f7..1fc5fe2e383f 100644 --- a/Android.bp +++ b/Android.bp @@ -771,6 +771,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", @@ -1210,11 +1228,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/animation/IntEvaluator.java b/core/java/android/animation/IntEvaluator.java index 34fb0dc57bda..1de2ae7326ed 100644 --- a/core/java/android/animation/IntEvaluator.java +++ b/core/java/android/animation/IntEvaluator.java @@ -24,7 +24,7 @@ public class IntEvaluator implements TypeEvaluator<Integer> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The - * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>, + * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * @@ -39,4 +39,4 @@ public class IntEvaluator implements TypeEvaluator<Integer> { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); } -}
\ No newline at end of file +} 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/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index d65e051b70b4..3120421622a4 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1120,6 +1120,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** @hide */ public String[] splitClassLoaderNames; + /** @hide */ + public boolean hiddenUntilInstalled; + /** * Represents the default policy. The actual policy used will depend on other properties of * the application, e.g. the target SDK version. @@ -1460,6 +1463,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { compileSdkVersion = orig.compileSdkVersion; compileSdkVersionCodename = orig.compileSdkVersionCodename; mHiddenApiPolicy = orig.mHiddenApiPolicy; + hiddenUntilInstalled = orig.hiddenUntilInstalled; } public String toString() { @@ -1534,6 +1538,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(compileSdkVersionCodename); dest.writeString(appComponentFactory); dest.writeInt(mHiddenApiPolicy); + dest.writeInt(hiddenUntilInstalled ? 1 : 0); } public static final Parcelable.Creator<ApplicationInfo> CREATOR @@ -1605,6 +1610,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { compileSdkVersionCodename = source.readString(); appComponentFactory = source.readString(); mHiddenApiPolicy = source.readInt(); + hiddenUntilInstalled = source.readInt() != 0; } /** diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index c988fa907f86..bc5b32c69b59 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -598,6 +598,9 @@ interface IPackageManager { boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId); boolean getApplicationHiddenSettingAsUser(String packageName, int userId); + void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden); + boolean setSystemAppInstallState(String packageName, boolean installed, int userId); + IPackageInstaller getPackageInstaller(); boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7253e7758008..68d0da970b63 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -147,6 +147,7 @@ public abstract class PackageManager { GET_DISABLED_COMPONENTS, GET_DISABLED_UNTIL_USED_COMPONENTS, GET_UNINSTALLED_PACKAGES, + MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, }) @Retention(RetentionPolicy.SOURCE) public @interface PackageInfoFlags {} @@ -164,6 +165,7 @@ public abstract class PackageManager { MATCH_STATIC_SHARED_LIBRARIES, GET_DISABLED_UNTIL_USED_COMPONENTS, GET_UNINSTALLED_PACKAGES, + MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoFlags {} @@ -522,6 +524,12 @@ public abstract class PackageManager { public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000; /** + * Internal flag used to indicate that a package is a hidden system app. + * @hide + */ + public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000; + + /** * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when * resolving an intent that matches the {@code CrossProfileIntentFilter}, * the current profile will be skipped. Only activities in the target user @@ -4841,7 +4849,8 @@ public abstract class PackageManager { * on the system for other users, also install it for the specified user. * @hide */ - @RequiresPermission(anyOf = { + @RequiresPermission(anyOf = { + Manifest.permission.INSTALL_EXISTING_PACKAGES, Manifest.permission.INSTALL_PACKAGES, Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 3f8a390c215e..79f3e53f1c9e 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -639,11 +639,19 @@ public class PackageParser { */ private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state, ApplicationInfo appInfo) { + // Returns false if the package is hidden system app until installed. + if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 + && !state.installed + && appInfo != null && appInfo.hiddenUntilInstalled) { + return false; + } + // If available for the target user, or trying to match uninstalled packages and it's // a system app. return state.isAvailable(flags) || (appInfo != null && appInfo.isSystemApp() - && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0); + && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 + || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); } public static boolean isAvailable(PackageUserState state) { 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/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index a040a09cf469..1ee3c933b326 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -82,9 +82,9 @@ import java.util.List; * * </ul> * - * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for - * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE} - * format may be used.</p> + * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats except + * {@link ImageFormat#JPEG} and {@link ImageFormat#RAW_PRIVATE} can be used for sharing, subject to + * device support. On prior API levels, only {@link ImageFormat#PRIVATE} format may be used.</p> * * @see CameraDevice#createCaptureSessionByOutputConfigurations * 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/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 01562b328ecc..6f1bd787587b 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -33,7 +33,6 @@ import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -487,8 +486,9 @@ public class TextToSpeech { * intent. The possible values for this extra are * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}. * - * @deprecated No longer in use. If client ise interested in information about what - * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices. + * @deprecated No longer in use. If client is interested in information about what + * changed, it should use the ACTION_CHECK_TTS_DATA + * intent to discover available voices. */ @Deprecated public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled"; diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index 47bda538ae52..496bc9ff5383 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -29,6 +29,7 @@ import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; +import android.graphics.Region.Op; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -325,14 +326,9 @@ public final class DisplayCutout { * @hide */ public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) { - Path path = new Path(); - path.reset(); - path.moveTo(left, top); - path.lineTo(left, bottom); - path.lineTo(right, bottom); - path.lineTo(right, top); - path.close(); - return fromBounds(path); + Region r = Region.obtain(); + r.set(left, top, right, bottom); + return fromBounds(r); } /** @@ -340,26 +336,19 @@ public final class DisplayCutout { * * @hide */ - public static DisplayCutout fromBounds(Path path) { - RectF clipRect = new RectF(); - path.computeBounds(clipRect, false /* unused */); - Region clipRegion = Region.obtain(); - clipRegion.set((int) clipRect.left, (int) clipRect.top, - (int) clipRect.right, (int) clipRect.bottom); - - Region bounds = new Region(); - bounds.setPath(path, clipRegion); - clipRegion.recycle(); - return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */); + public static DisplayCutout fromBounds(Region region) { + return new DisplayCutout(ZERO_RECT, region, false /* copyArguments */); } /** - * Creates the bounding path according to @android:string/config_mainBuiltInDisplayCutout. + * Creates the display cutout according to + * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest + * rectangle-base approximation of the cutout. * * @hide */ - public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) { - return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), + public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) { + return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation), displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT); } @@ -369,7 +358,8 @@ public final class DisplayCutout { * @hide */ public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) { - return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), + return pathAndDisplayCutoutFromSpec( + res.getString(R.string.config_mainBuiltInDisplayCutout), displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT).first; } @@ -417,6 +407,7 @@ public final class DisplayCutout { } final Path p; + final Region r = Region.obtain(); try { p = PathParser.createPathFromPathData(spec); } catch (Throwable e) { @@ -431,6 +422,8 @@ public final class DisplayCutout { m.postTranslate(offsetX, 0); p.transform(m); + addToRegion(p, r); + if (bottomSpec != null) { final Path bottomPath; try { @@ -443,9 +436,10 @@ public final class DisplayCutout { m.postTranslate(0, displayHeight); bottomPath.transform(m); p.addPath(bottomPath); + addToRegion(bottomPath, r); } - final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(p)); + final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r)); synchronized (CACHE_LOCK) { sCachedSpec = spec; sCachedDisplayWidth = displayWidth; @@ -456,6 +450,14 @@ public final class DisplayCutout { return result; } + private static void addToRegion(Path p, Region r) { + final RectF rectF = new RectF(); + final Rect rect = new Rect(); + p.computeBounds(rectF, false /* unused */); + rectF.round(rect); + r.op(rect, Op.UNION); + } + private static Region boundingRectsToRegion(List<Rect> rects) { Region result = Region.obtain(); if (rects != null) { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index d7f1d6e3b2d1..0c103e50ee45 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -143,7 +143,7 @@ import java.util.Map; * This class is called when something that might impact a * browser UI happens, for instance, progress updates and * JavaScript alerts are sent here (see <a - * href="{@docRoot}guide/developing/debug-tasks.html#DebuggingWebPages">Debugging Tasks</a>). + * href="{@docRoot}guide/webapps/debugging.html">Debugging Web Apps</a>). * </li> * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass. * It will be called when things happen that impact the 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/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 13729874d369..67b7100ab9ba 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -80,7 +80,7 @@ import java.io.IOException; * * <p> * To learn more about Drawables, see: <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. - * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.htm">Handling Bitmaps</a>. + * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.html">Handling Bitmaps</a>. * </p> * * @attr ref android.R.styleable#ImageView_adjustViewBounds diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index f6a69d9aeb93..57785443919e 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -18,6 +18,9 @@ package com.android.internal.app; import android.animation.TimeAnimator; import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.ContentResolver; +import android.content.Intent; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -25,12 +28,15 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.provider.Settings; import android.util.Log; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.View; import android.widget.FrameLayout; +import org.json.JSONObject; + public class PlatLogoActivity extends Activity { FrameLayout layout; TimeAnimator anim; @@ -87,7 +93,7 @@ public class PlatLogoActivity extends Activity { darkest = 0; for (int i=0; i<slots; i++) { palette[i] = Color.HSVToColor(color); - color[0] += 360f/slots; + color[0] = (color[0] + 360f/slots) % 360f; if (lum(palette[i]) < lum(palette[darkest])) darkest = i; } @@ -178,27 +184,97 @@ public class PlatLogoActivity extends Activity { bg = new PBackground(); layout.setBackground(bg); + final ContentResolver cr = getContentResolver(); + layout.setOnTouchListener(new View.OnTouchListener() { + final String TOUCH_STATS = "touch.stats"; + final PointerCoords pc0 = new PointerCoords(); final PointerCoords pc1 = new PointerCoords(); + double pressure_min, pressure_max; + int maxPointers; + int tapCount; + @Override public boolean onTouch(View v, MotionEvent event) { + final float pressure = event.getPressure(); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: + pressure_min = pressure_max = pressure; + // fall through case MotionEvent.ACTION_MOVE: - if (event.getPointerCount() > 1) { + if (pressure < pressure_min) pressure_min = pressure; + if (pressure > pressure_max) pressure_max = pressure; + final int pc = event.getPointerCount(); + if (pc > maxPointers) maxPointers = pc; + if (pc > 1) { event.getPointerCoords(0, pc0); event.getPointerCoords(1, pc1); bg.setRadius((float) Math.hypot(pc0.x - pc1.x, pc0.y - pc1.y) / 2f); } break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + try { + final String touchDataJson = Settings.System.getString(cr, TOUCH_STATS); + final JSONObject touchData = new JSONObject( + touchDataJson != null ? touchDataJson : "{}"); + if (touchData.has("min")) { + pressure_min = Math.min(pressure_min, touchData.getDouble("min")); + } + if (touchData.has("max")) { + pressure_max = Math.max(pressure_max, touchData.getDouble("max")); + } + touchData.put("min", pressure_min); + touchData.put("max", pressure_max); + Settings.System.putString(cr, TOUCH_STATS, touchData.toString()); + } catch (Exception e) { + Log.e("PlatLogoActivity", "Can't write touch settings", e); + } + + if (maxPointers == 1) { + tapCount ++; + if (tapCount < 7) { + bg.randomizePalette(); + } else { + launchNextStage(); + } + } else { + tapCount = 0; + } + maxPointers = 0; + break; } return true; } }); } + private void launchNextStage() { + final ContentResolver cr = getContentResolver(); + + if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0) == 0) { + // For posterity: the moment this user unlocked the easter egg + try { + Settings.System.putLong(cr, + Settings.System.EGG_MODE, + System.currentTimeMillis()); + } catch (RuntimeException e) { + Log.e("PlatLogoActivity", "Can't write settings", e); + } + } + try { + startActivity(new Intent(Intent.ACTION_MAIN) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK) + .addCategory("com.android.internal.category.PLATLOGO")); + } catch (ActivityNotFoundException ex) { + Log.e("PlatLogoActivity", "No more eggs."); + } + finish(); + } + @Override public void onStart() { super.onStart(); 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/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index caf4e4b48e61..e30a3e7adc0c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -45,6 +45,7 @@ #include <unistd.h> #include "android-base/logging.h" +#include <android-base/properties.h> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <cutils/fs.h> @@ -70,6 +71,7 @@ namespace { using android::String8; using android::base::StringPrintf; using android::base::WriteStringToFile; +using android::base::GetBoolProperty; #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ append(StringPrintf(__VA_ARGS__)) @@ -931,12 +933,16 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!"); } - // Assign system_server to the correct memory cgroup. - // Not all devices mount /dev/memcg so check for the file first - // to avoid unnecessarily printing errors and denials in the logs. - if (!access("/dev/memcg/system/tasks", F_OK) && + bool low_ram_device = GetBoolProperty("ro.config.low_ram", false); + bool per_app_memcg = GetBoolProperty("ro.config.per_app_memcg", low_ram_device); + if (per_app_memcg) { + // Assign system_server to the correct memory cgroup. + // Not all devices mount /dev/memcg so check for the file first + // to avoid unnecessarily printing errors and denials in the logs. + if (!access("/dev/memcg/system/tasks", F_OK) && !WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) { - ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid); + ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid); + } } } return pid; diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 7467d8f2e961..2de53b97312a 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -319,6 +319,8 @@ message WindowStateProto { optional bool removed = 36; optional bool is_on_screen = 37; optional bool is_visible = 38; + optional bool pending_forced_seamless_rotation = 39; + optional int64 finished_forced_seamless_rotation_frame = 40; } message IdentifierProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 66c497e99776..cda1293e93c7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2238,7 +2238,8 @@ android:description="@string/permdesc_install_shortcut" android:protectionLevel="normal"/> - <!--This permission is no longer supported. + <!-- <p class="caution"><strong>Don't use this permission in your app.</strong><br>This + permission is no longer supported. --> <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" android:label="@string/permlab_uninstall_shortcut" @@ -3024,6 +3025,15 @@ <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES" android:protectionLevel="signature|privileged" /> + <!-- Allows an application to install existing system packages. This is a limited + version of {@link android.Manifest.permission#INSTALL_PACKAGES}. + <p>Not for use by third-party applications. + TODO(b/80204953): remove this permission once we have a long-term solution. + @hide + --> + <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES" + android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows an application to clear user data. <p>Not for use by third-party applications @hide diff --git a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml index e9475f52d22a..ff95aeae1683 100644 --- a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml +++ b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml @@ -16,7 +16,6 @@ --> <alpha xmlns:android="http://schemas.android.com/apk/res/android" - android:background="#ff000000" android:detachWallpaper="true" android:shareInterpolator="false" android:interpolator="@interpolator/linear" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 9d366942aa1b..b85466671b66 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -42,13 +42,13 @@ <item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item> <item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item> <item><xliff:g id="id">@string/status_bar_secure</xliff:g></item> - <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item> <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item> <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item> <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item> + <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item> + <item><xliff:g id="id">@string/status_bar_location</xliff:g></item> <item><xliff:g id="id">@string/status_bar_mute</xliff:g></item> <item><xliff:g id="id">@string/status_bar_volume</xliff:g></item> - <item><xliff:g id="id">@string/status_bar_location</xliff:g></item> <item><xliff:g id="id">@string/status_bar_zen</xliff:g></item> <item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item> <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item> @@ -667,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> @@ -2093,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> @@ -2939,6 +2961,14 @@ --> <string translatable="false" name="config_mainBuiltInDisplayCutout"></string> + <!-- Like config_mainBuiltInDisplayCutout, but this path is used to report the + one single bounding rect per device edge to the app via + {@link DisplayCutout#getBoundingRect}. Note that this path should try to match the visual + appearance of the cutout as much as possible, and may be smaller than + config_mainBuiltInDisplayCutout + --> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> @@ -3455,4 +3485,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/strings.xml b/core/res/res/values/strings.xml index 3c5159c89bf6..f6600462ea74 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3169,6 +3169,21 @@ <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. --> <string name="wifi_no_internet_detailed">Tap for options</string> + <!-- A notification is shown when the user's softap config has been changed due to underlying + hardware restrictions. This is the notifications's title. + [CHAR_LIMIT=NONE] --> + <string name="wifi_softap_config_change">Changes to your hotspot settings</string> + + <!-- A notification is shown when the user's softap config has been changed due to underlying + hardware restrictions. This is the notification's summary message. + [CHAR_LIMIT=NONE] --> + <string name="wifi_softap_config_change_summary">Your hotspot band has changed.</string> + + <!-- A notification is shown when the user's softap config has been changed due to underlying + hardware restrictions. This is the notification's full message. + [CHAR_LIMIT=NONE] --> + <string name="wifi_softap_config_change_detailed">This device doesn\u2019t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.</string> + <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. --> <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 65606e31387a..f3d443106d4f 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" /> @@ -1055,6 +1061,9 @@ <java-symbol type="string" name="network_switch_type_name_unknown" /> <java-symbol type="string" name="wifi_no_internet" /> <java-symbol type="string" name="wifi_no_internet_detailed" /> + <java-symbol type="string" name="wifi_softap_config_change" /> + <java-symbol type="string" name="wifi_softap_config_change_summary" /> + <java-symbol type="string" name="wifi_softap_config_change_detailed" /> <java-symbol type="string" name="wifi_connect_alert_title" /> <java-symbol type="string" name="wifi_connect_alert_message" /> <java-symbol type="string" name="wifi_connect_default_application" /> @@ -2194,6 +2203,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" /> @@ -3232,6 +3242,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" /> @@ -3327,6 +3338,7 @@ <java-symbol type="string" name="global_action_logout" /> <java-symbol type="string" name="config_mainBuiltInDisplayCutout" /> + <java-symbol type="string" name="config_mainBuiltInDisplayCutoutRectApproximation" /> <java-symbol type="drawable" name="messaging_user" /> <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" /> <java-symbol type="drawable" name="ic_logout" /> 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/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index 2b5a37bd84e2..4c007cb70ba2 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -811,7 +811,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } int errorCode = mKeyStore.importWrappedKey( - Credentials.USER_SECRET_KEY + alias, + Credentials.USER_PRIVATE_KEY + alias, entry.getWrappedKeyBytes(), Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(), maskingKey, diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index b2e0f675f5f9..553e86e175d1 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -268,6 +268,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private final boolean mIsStrongBoxBacked; private final boolean mUserConfirmationRequired; private final boolean mUnlockedDeviceRequired; + /* + * ***NOTE***: All new fields MUST also be added to the following: + * ParcelableKeyGenParameterSpec class. + * The KeyGenParameterSpec.Builder constructor that takes a KeyGenParameterSpec + */ /** * @hide should be built with Builder @@ -791,6 +796,9 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded(); mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody(); mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment(); + mIsStrongBoxBacked = sourceSpec.isStrongBoxBacked(); + mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired(); + mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired(); } /** diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java index 911bbf8c4eb5..8231dc984579 100644 --- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java @@ -97,11 +97,14 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { out.writeBoolean(mSpec.isRandomizedEncryptionRequired()); out.writeBoolean(mSpec.isUserAuthenticationRequired()); out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds()); + out.writeBoolean(mSpec.isUserPresenceRequired()); out.writeByteArray(mSpec.getAttestationChallenge()); out.writeBoolean(mSpec.isUniqueIdIncluded()); out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody()); out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment()); - out.writeBoolean(mSpec.isUserPresenceRequired()); + out.writeBoolean(mSpec.isStrongBoxBacked()); + out.writeBoolean(mSpec.isUserConfirmationRequired()); + out.writeBoolean(mSpec.isUnlockedDeviceRequired()); } private static Date readDateOrNull(Parcel in) { @@ -114,19 +117,12 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { } private ParcelableKeyGenParameterSpec(Parcel in) { - String keystoreAlias = in.readString(); - int purposes = in.readInt(); - KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder( - keystoreAlias, purposes); - builder.setUid(in.readInt()); - // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default - // value, do not set it as this will cause setKeySize to throw. - int keySize = in.readInt(); - if (keySize >= 0) { - builder.setKeySize(keySize); - } + final String keystoreAlias = in.readString(); + final int purposes = in.readInt(); + final int uid = in.readInt(); + final int keySize = in.readInt(); - int keySpecType = in.readInt(); + final int keySpecType = in.readInt(); AlgorithmParameterSpec algorithmSpec = null; if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) { algorithmSpec = null; @@ -141,32 +137,60 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { throw new IllegalArgumentException( String.format("Unknown algorithm parameter spec: %d", keySpecType)); } - if (algorithmSpec != null) { - builder.setAlgorithmParameterSpec(algorithmSpec); - } - builder.setCertificateSubject(new X500Principal(in.createByteArray())); - builder.setCertificateSerialNumber(new BigInteger(in.createByteArray())); - builder.setCertificateNotBefore(new Date(in.readLong())); - builder.setCertificateNotAfter(new Date(in.readLong())); - builder.setKeyValidityStart(readDateOrNull(in)); - builder.setKeyValidityForOriginationEnd(readDateOrNull(in)); - builder.setKeyValidityForConsumptionEnd(readDateOrNull(in)); - String[] digests = in.createStringArray(); - if (digests != null) { - builder.setDigests(digests); - } - builder.setEncryptionPaddings(in.createStringArray()); - builder.setSignaturePaddings(in.createStringArray()); - builder.setBlockModes(in.createStringArray()); - builder.setRandomizedEncryptionRequired(in.readBoolean()); - builder.setUserAuthenticationRequired(in.readBoolean()); - builder.setUserAuthenticationValidityDurationSeconds(in.readInt()); - builder.setAttestationChallenge(in.createByteArray()); - builder.setUniqueIdIncluded(in.readBoolean()); - builder.setUserAuthenticationValidWhileOnBody(in.readBoolean()); - builder.setInvalidatedByBiometricEnrollment(in.readBoolean()); - builder.setUserPresenceRequired(in.readBoolean()); - mSpec = builder.build(); + + final X500Principal certificateSubject = new X500Principal(in.createByteArray()); + final BigInteger certificateSerialNumber = new BigInteger(in.createByteArray()); + final Date certificateNotBefore = new Date(in.readLong()); + final Date certificateNotAfter = new Date(in.readLong()); + final Date keyValidityStartDate = readDateOrNull(in); + final Date keyValidityForOriginationEnd = readDateOrNull(in); + final Date keyValidityForConsumptionEnd = readDateOrNull(in); + final String[] digests = in.createStringArray(); + final String[] encryptionPaddings = in.createStringArray(); + final String[] signaturePaddings = in.createStringArray(); + final String[] blockModes = in.createStringArray(); + final boolean randomizedEncryptionRequired = in.readBoolean(); + final boolean userAuthenticationRequired = in.readBoolean(); + final int userAuthenticationValidityDurationSeconds = in.readInt(); + final boolean userPresenceRequired = in.readBoolean(); + final byte[] attestationChallenge = in.createByteArray(); + final boolean uniqueIdIncluded = in.readBoolean(); + final boolean userAuthenticationValidWhileOnBody = in.readBoolean(); + final boolean invalidatedByBiometricEnrollment = in.readBoolean(); + final boolean isStrongBoxBacked = in.readBoolean(); + final boolean userConfirmationRequired = in.readBoolean(); + final boolean unlockedDeviceRequired = in.readBoolean(); + // The KeyGenParameterSpec is intentionally not constructed using a Builder here: + // The intention is for this class to break if new parameters are added to the + // KeyGenParameterSpec constructor (whereas using a builder would silently drop them). + mSpec = new KeyGenParameterSpec( + keystoreAlias, + uid, + keySize, + algorithmSpec, + certificateSubject, + certificateSerialNumber, + certificateNotBefore, + certificateNotAfter, + keyValidityStartDate, + keyValidityForOriginationEnd, + keyValidityForConsumptionEnd, + purposes, + digests, + encryptionPaddings, + signaturePaddings, + blockModes, + randomizedEncryptionRequired, + userAuthenticationRequired, + userAuthenticationValidityDurationSeconds, + userPresenceRequired, + attestationChallenge, + uniqueIdIncluded, + userAuthenticationValidWhileOnBody, + invalidatedByBiometricEnrollment, + isStrongBoxBacked, + userConfirmationRequired, + unlockedDeviceRequired); } public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() { diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java index 254b6be77ea8..32f8ec44d11f 100644 --- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java @@ -77,6 +77,9 @@ public final class ParcelableKeyGenParameterSpecTest { .setUniqueIdIncluded(true) .setUserAuthenticationValidWhileOnBody(true) .setInvalidatedByBiometricEnrollment(true) + .setIsStrongBoxBacked(true) + .setUserConfirmationRequired(true) + .setUnlockedDeviceRequired(true) .build(); } @@ -105,6 +108,9 @@ public final class ParcelableKeyGenParameterSpecTest { assertThat(spec.isUniqueIdIncluded(), is(true)); assertThat(spec.isUserAuthenticationValidWhileOnBody(), is(true)); assertThat(spec.isInvalidatedByBiometricEnrollment(), is(true)); + assertThat(spec.isStrongBoxBacked(), is(true)); + assertThat(spec.isUserConfirmationRequired(), is(true)); + assertThat(spec.isUnlockedDeviceRequired(), is(true)); } private Parcel parcelForReading(ParcelableKeyGenParameterSpec spec) { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp index 107890e57a19..0760f1610891 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -26,6 +26,7 @@ #include "DeviceInfo.h" #include "Matrix.h" #include "Properties.h" +#include "utils/MathUtils.h" using namespace android::uirenderer::renderthread; @@ -116,9 +117,9 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 paint.setBlendMode(SkBlendMode::kSrc); // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage // is codified by tests using golden images like DecodeAccuracyTest. - if (skiaSrcRect.width() != bitmap->width() || - skiaSrcRect.height() != bitmap->height()) { - // TODO: apply filter always, but check if tests will be fine + bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) + && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height()); + if (!disableFilter) { paint.setFilterQuality(kLow_SkFilterQuality); } scaledSurface->getCanvas()->concat(textureMatrix); 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/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index c36858ad3d8e..a45aa90f5f19 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -612,8 +612,12 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) { Image_setBufferItem(env, image, buffer); env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, static_cast<jlong>(buffer->mTimestamp)); + auto transform = buffer->mTransform; + if (buffer->mTransformToDisplayInverse) { + transform |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; + } env->SetIntField(image, gSurfaceImageClassInfo.mTransform, - static_cast<jint>(buffer->mTransform)); + static_cast<jint>(transform)); env->SetIntField(image, gSurfaceImageClassInfo.mScalingMode, static_cast<jint>(buffer->mScalingMode)); diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp new file mode 100644 index 000000000000..43ed810b5674 --- /dev/null +++ b/packages/EasterEgg/Android.bp @@ -0,0 +1,33 @@ +// +// 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. +// + +android_app { + // the build system in pi-dev can't quite handle R.java in kt + // so we will have a mix of java and kotlin files + srcs: ["src/**/*.java", "src/**/*.kt"], + + resource_dirs: ["res"], + + name: "EasterEgg", + + certificate: "platform", + + sdk_version: "current", + + optimize: { + enabled: false, + } +} diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk deleted file mode 100644 index 605a75d16977..000000000000 --- a/packages/EasterEgg/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional - -LOCAL_STATIC_JAVA_LIBRARIES := \ - jsr305 - -LOCAL_STATIC_ANDROID_LIBRARIES := \ - android-support-v4 \ - android-support-v13 \ - android-support-dynamic-animation \ - android-support-v7-recyclerview \ - android-support-v7-preference \ - android-support-v7-appcompat \ - android-support-v14-preference - -LOCAL_USE_AAPT2 := true - -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PACKAGE_NAME := EasterEgg -LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_CERTIFICATE := platform - -include $(BUILD_PACKAGE) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml index 172490dc9178..6651d9a930f3 100644 --- a/packages/EasterEgg/AndroidManifest.xml +++ b/packages/EasterEgg/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2016 The Android Open Source Project + Copyright (C) 2018 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); + 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 @@ -15,85 +15,28 @@ Copyright (C) 2016 The Android Open Source Project limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.egg" - android:versionCode="1" - android:versionName="1.0"> + package="com.android.egg" + android:versionCode="1" + android:versionName="1.0"> - <uses-sdk android:minSdkVersion="26" /> + <uses-sdk android:minSdkVersion="28" /> - <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <application + android:icon="@drawable/icon" + android:label="@string/app_name"> - <application android:label="@string/app_name" android:icon="@drawable/icon"> - - <activity android:name=".octo.Ocquarium" - android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen" - android:label="@string/app_name"> - <intent-filter> - <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="com.android.internal.category.PLATLOGO" /> - </intent-filter> - </activity> - - <!-- Android N lives on inside Android O... --> - - <!-- Long press the QS tile to get here --> - <activity android:name=".neko.NekoLand" - android:theme="@android:style/Theme.Material.NoActionBar" - android:label="@string/app_name"> + <activity + android:name=".paint.PaintActivity" + android:configChanges="orientation|keyboardHidden|screenSize|uiMode" + android:label="@string/app_name" + android:theme="@style/AppTheme"> <intent-filter> - <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" /> <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <!-- This is where the magic happens --> - <service - android:name=".neko.NekoService" - android:enabled="true" - android:permission="android.permission.BIND_JOB_SERVICE" - android:exported="true" > - </service> - - <!-- Used to show over lock screen --> - <activity android:name=".neko.NekoLockedActivity" - android:excludeFromRecents="true" - android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar" - android:showOnLockScreen="true" /> - - <!-- Used to enable easter egg --> - <activity android:name=".neko.NekoActivationActivity" - android:excludeFromRecents="true" - android:theme="@android:style/Theme.NoDisplay" - > - <intent-filter> - <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.DEFAULT" /> + <!--<category android:name="android.intent.category.LAUNCHER" />--> + <category android:name="com.android.internal.category.PLATLOGO" /> </intent-filter> </activity> - - <!-- The quick settings tile, disabled by default --> - <service - android:name=".neko.NekoTile" - android:permission="android.permission.BIND_QUICK_SETTINGS_TILE" - android:icon="@drawable/stat_icon" - android:enabled="false" - android:label="@string/default_tile_name"> - <intent-filter> - <action android:name="android.service.quicksettings.action.QS_TILE" /> - </intent-filter> - </service> - - <!-- FileProvider for sending pictures --> - <provider - android:name="android.support.v4.content.FileProvider" - android:authorities="com.android.egg.fileprovider" - android:grantUriPermissions="true" - android:exported="false"> - <meta-data - android:name="android.support.FILE_PROVIDER_PATHS" - android:resource="@xml/filepaths" /> - </provider> </application> -</manifest> + +</manifest>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/leg1.xml b/packages/EasterEgg/res/color-night/toolbar_icon_color.xml index d72c746b6232..c0a81520f849 100644 --- a/packages/EasterEgg/res/drawable/leg1.xml +++ b/packages/EasterEgg/res/color-night/toolbar_icon_color.xml @@ -1,7 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2016 The Android Open Source Project + Copyright (C) 2018 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); + 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 @@ -13,10 +14,7 @@ Copyright (C) 2016 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="leg1" android:fillColor="#FF000000" android:pathData="M9,37h5v6h-5z"/> -</vector> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="#FFFF3333" android:state_selected="true" /> + <item android:color="#FFFFFFFF" /> +</selector>
\ No newline at end of file diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/color/toolbar_icon_color.xml index e9dcebd27f7b..d3247e406a91 100644 --- a/packages/EasterEgg/res/values/dimens.xml +++ b/packages/EasterEgg/res/color/toolbar_icon_color.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2016 The Android Open Source Project +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. @@ -14,6 +14,7 @@ Copyright (C) 2016 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<resources xmlns:android="http://schemas.android.com/apk/res/android"> - <dimen name="neko_display_size">64dp</dimen> -</resources> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="#FFCC0000" android:state_selected="true" /> + <item android:color="#FF000000" /> +</selector>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/back.xml b/packages/EasterEgg/res/drawable/back.xml deleted file mode 100644 index b55d65cdf76d..000000000000 --- a/packages/EasterEgg/res/drawable/back.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="back" android:fillColor="#FF000000" android:pathData="M37.1,22c-1.1,0 -1.9,0.8 -1.9,1.9v5.6c0,1.1 0.8,1.9 1.9,1.9H39v-1.9v-5.6V22H37.1z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/belly.xml b/packages/EasterEgg/res/drawable/belly.xml deleted file mode 100644 index 8b0e9afac463..000000000000 --- a/packages/EasterEgg/res/drawable/belly.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="belly" android:fillColor="#FF000000" android:pathData="M20.5,25c-3.6,0 -6.5,2.9 -6.5,6.5V38h13v-6.5C27,27.9 24.1,25 20.5,25z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/cap.xml b/packages/EasterEgg/res/drawable/cap.xml deleted file mode 100644 index d8b4cc58a261..000000000000 --- a/packages/EasterEgg/res/drawable/cap.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="cap" android:fillColor="#FF000000" android:pathData="M27.2,3.8c-1,-0.2 -2.1,-0.3 -3.2,-0.3s-2.1,0.1 -3.2,0.3c0.2,1.3 1.5,2.2 3.2,2.2C25.6,6.1 26.9,5.1 27.2,3.8z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/collar.xml b/packages/EasterEgg/res/drawable/collar.xml deleted file mode 100644 index 5e4d0fd4f886..000000000000 --- a/packages/EasterEgg/res/drawable/collar.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="collar" android:fillColor="#FF000000" android:pathData="M9,18.4h30v1.7h-30z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/face_spot.xml b/packages/EasterEgg/res/drawable/face_spot.xml deleted file mode 100644 index a89fb4fdaadd..000000000000 --- a/packages/EasterEgg/res/drawable/face_spot.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="face_spot" android:fillColor="#FF000000" android:pathData="M19.5,15.2a4.5,3.2 0,1 0,9 0a4.5,3.2 0,1 0,-9 0z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/food_bits.xml b/packages/EasterEgg/res/drawable/food_bits.xml deleted file mode 100644 index 1b2bb6f36947..000000000000 --- a/packages/EasterEgg/res/drawable/food_bits.xml +++ /dev/null @@ -1,33 +0,0 @@ -<!-- -Copyright (C) 2015 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M19.1,34l-3.5,1.3c-1,0.4,-2.2,-0.1,-2.6,-1.1l-1.2,-3c-0.4,-1,0.1,-2.2,1.1,-2.6l3.5,-1.3c1,-0.4,2.2,0.1,2.6,1.1l1.2,3 C20.6,32.4,20.1,33.6,19.1,34z"/> - <path - android:fillColor="#FF000000" - android:pathData="M25.2,28.1L22.9,28c-0.8,0,-1.5,-0.7,-1.4,-1.6l0.1,-2c0,-0.8,0.7,-1.5,1.6,-1.4l2.4,0.1c0.8,0,1.5,0.7,1.4,1.6l-0.1,2 C26.8,27.5,26.1,28.1,25.2,28.1z"/> - <path - android:fillColor="#FF000000" - android:pathData="M18.7,23.1L16.5,23c-0.5,0,-0.9,-0.4,-0.8,-0.9l0.1,-2.2c0,-0.5,0.4,-0.9,0.9,-0.8l2.2,0.1c0.5,0,0.9,0.4,0.8,0.9 l-0.1,2.2C19.6,22.8,19.2,23.1,18.7,23.1z"/> - <path - android:fillColor="#FF000000" - android:pathData="M32.2,35.3l-3.6,-1.8c-1,-0.5,-1.4,-1.7,-0.9,-2.7l1.6,-3.1c0.5,-1,1.7,-1.4,2.7,-0.9l3.6,1.8c1,0.5,1.4,1.7,0.9,2.7 l-1.6,3.1C34.4,35.4,33.2,35.7,32.2,35.3z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/food_chicken.xml b/packages/EasterEgg/res/drawable/food_chicken.xml deleted file mode 100644 index 95b2fb55b796..000000000000 --- a/packages/EasterEgg/res/drawable/food_chicken.xml +++ /dev/null @@ -1,39 +0,0 @@ -<!-- -Copyright (C) 2015 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M9,12v14h10V11H9z M11.7,16.3c-0.7,0,-1.3,-0.6,-1.3,-1.3s0.6,-1.3,1.3,-1.3S13,14.3,13,15S12.4,16.3,11.7,16.3z"/> - <path - android:fillColor="#FF000000" - android:pathData="M5.7,20.1l1.6,-3.0l-1.6,-3.0l4.4,3.0z"/> - <path - android:fillColor="#FF000000" - android:pathData="M19.0,6.0l-2.3,2.3l-2.7,-2.6l-2.7,2.6l-2.3,-2.3l0.0,4.0l10.0,0.0z"/> - <path - android:fillColor="#FF000000" - android:pathData="M9,25c0,8.3,6.7,15,15,15s15,-6.7,15,-15H9z M29.9,31.5h-11v-1h12L29.9,31.5z M31.9,29.5h-13v-1h14L31.9,29.5z M33.9,27.5 h-15v-1h16L33.9,27.5z"/> - <path - android:fillColor="#FF000000" - android:pathData="M27.0,38.6h2.0v6.0h-2.0z"/> - <path - android:fillColor="#FF000000" - android:pathData="M17.4,44.6l-2.1999998,0.0l4.4000006,-6.0l2.1999989,0.0z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/food_cookie.xml b/packages/EasterEgg/res/drawable/food_cookie.xml deleted file mode 100644 index 74dd134355e2..000000000000 --- a/packages/EasterEgg/res/drawable/food_cookie.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright (C) 2017 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <group> - <path - android:fillColor="#55FFFFFF" - android:fillType="evenOdd" - android:pathData="M5.71 18.29A8.99 8.99 0 0 0 22 13c0-3-1.46-5.65-3.71-7.29A8.99 8.99 0 0 0 2 11c0 3 1.46 5.65 3.71 7.29z"/> - <path - android:fillColor="#FFFFFFFF" - android:fillType="evenOdd" - android:pathData="M7.25 19.18A8.5 8.5 0 0 0 19.19 7.24 9 9 0 0 1 7.24 19.19z"/> - <path - android:fillColor="#55FFFFFF" - android:pathData="M10.5 3a0.5 0.5 0 1 1 1 0v2.05a0.5 0.5 0 1 1-1 0V3zm3.1 0.42a0.5 0.5 0 0 1 0.93 0.39l-0.8 1.88A0.5 0.5 0 1 1 12.8 5.3l0.8-1.88zm2.7 1.57a0.5 0.5 0 1 1 0.71 0.7l-1.45 1.46a0.5 0.5 0 0 1-0.7-0.71l1.44-1.45zm1.9 2.5a0.5 0.5 0 0 1 0.38 0.92l-1.9 0.77a0.5 0.5 0 0 1-0.37-0.93l1.9-0.77zM19 10.5a0.5 0.5 0 1 1 0 1h-2.05a0.5 0.5 0 0 1 0-1H19zm-0.42 3.1a0.5 0.5 0 0 1-0.39 0.93l-1.88-0.8a0.5 0.5 0 1 1 0.39-0.92l1.88 0.8zm-1.57 2.7a0.5 0.5 0 1 1-0.7 0.71l-1.46-1.45a0.5 0.5 0 0 1 0.71-0.7l1.45 1.44zm-2.5 1.9a0.5 0.5 0 1 1-0.92 0.38l-0.77-1.9a0.5 0.5 0 0 1 0.93-0.37l0.77 1.9zM11.5 19a0.5 0.5 0 1 1-1 0v-2.05a0.5 0.5 0 0 1 1 0V19zm-3.1-0.42a0.5 0.5 0 0 1-0.93-0.39l0.8-1.88A0.5 0.5 0 0 1 9.2 16.7l-0.8 1.88zm-2.7-1.57a0.5 0.5 0 1 1-0.71-0.7l1.45-1.46a0.5 0.5 0 0 1 0.7 0.71L5.7 17.01zm-1.9-2.48a0.5 0.5 0 0 1-0.38-0.92l1.88-0.8a0.5 0.5 0 0 1 0.4 0.92l-1.9 0.8zM3 11.5a0.5 0.5 0 1 1 0-1h2.05a0.5 0.5 0 1 1 0 1H3zm0.42-3.1A0.5 0.5 0 0 1 3.8 7.46l1.88 0.8A0.5 0.5 0 1 1 5.3 9.2L3.42 8.4zm1.57-2.7a0.5 0.5 0 1 1 0.7-0.71l1.46 1.45a0.5 0.5 0 0 1-0.71 0.7L4.99 5.7zm2.5-1.9A0.5 0.5 0 0 1 8.4 3.41l0.77 1.9a0.5 0.5 0 0 1-0.93 0.37L7.48 3.8z"/> - </group> -</vector>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/food_dish.xml b/packages/EasterEgg/res/drawable/food_dish.xml deleted file mode 100644 index 3fff6a90fad2..000000000000 --- a/packages/EasterEgg/res/drawable/food_dish.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- -Copyright (C) 2015 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M24,13.8C11.3,13.8,1,18.3,1,24c0,5.7,10.3,10.2,23,10.2S47,29.7,47,24C47,18.3,36.7,13.8,24,13.8z M33.7,26.6 c1.1,-0.6,1.8,-1.3,1.8,-2c0,-2.1,-5.2,-3.8,-11.7,-3.8s-11.7,1.7,-11.7,3.8c0,0.6,0.4,1.2,1.2,1.7c-1.7,-0.8,-2.8,-1.7,-2.8,-2.8 c0,-2.5,6,-4.5,13.4,-4.5s13.4,2,13.4,4.5C37.4,24.7,36,25.8,33.7,26.6z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/food_donut.xml b/packages/EasterEgg/res/drawable/food_donut.xml deleted file mode 100644 index eaf831ea560c..000000000000 --- a/packages/EasterEgg/res/drawable/food_donut.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- -Copyright (C) 2015 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M24,4.5c-10.5,0,-19,8.5,-19,19s8.5,19,19,19s19,-8.5,19,-19S34.5,4.5,24,4.5z M35.2,15.5l1.6,-1.1 c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1 C34.9,16.1,35,15.7,35.2,15.5z M32.7,10.7c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0 c-0.3,0,-0.5,-0.3,-0.5,-0.6L32.7,10.7z M31.7,15.1l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C31.3,15.4,31.5,15.2,31.7,15.1z M28.8,10.6l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1C28.4,11.1,28.5,10.8,28.8,10.6z M25.8,6 c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6L25.8,6z M20.7,6.5l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1 C20.3,6.9,20.4,6.6,20.7,6.5z M19.9,10.9l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C19.5,11.1,19.7,10.9,19.9,10.9z M16,10.9L16,10.9c0.2,-0.3,0.4,-0.4,0.6,-0.3l1.3,0.7 c0.2,0.1,0.3,0.4,0.2,0.6L18,12c-0.1,0.2,-0.4,0.3,-0.6,0.2l-1.3,-0.7C15.9,11.4,15.8,11.1,16,10.9z M15.8,18.5c0.2,0,0.4,0.1,0.5,0.4 l0,0.1c0,0.2,-0.1,0.4,-0.4,0.5l-1.5,0.2c-0.2,0,-0.4,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.4,0.4,-0.5L15.8,18.5z M14,21.8l-1.6,1.1 c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 C14.3,21.3,14.3,21.6,14,21.8z M12.4,12L12.4,12c0.3,-0.2,0.5,-0.2,0.7,-0.1l1,1.1c0.2,0.2,0.2,0.4,0,0.6L14,13.7 c-0.2,0.2,-0.4,0.2,-0.6,0l-1,-1.1C12.2,12.4,12.2,12.1,12.4,12z M8.3,24.5c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6 l0.2,-2c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6L8.3,24.5z M8.5,16.2v-0.1c0,-0.3,0.2,-0.6,0.6,-0.6h2 c0.3,0,0.6,0.2,0.6,0.6v0.1c0,0.3,-0.2,0.6,-0.6,0.6H9C8.7,16.7,8.5,16.5,8.5,16.2z M10.3,20.7c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1 c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8L10.3,20.7z M11.3,28.3l0,-0.1 c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7L12,28.6C11.7,28.7,11.4,28.6,11.3,28.3z M14.4,33c0,0.2,-0.2,0.4,-0.4,0.4h-1.5c-0.2,0,-0.4,-0.2,-0.4,-0.4v-0.1c0,-0.2,0.2,-0.4,0.4,-0.4H14c0.2,0,0.4,0.2,0.4,0.4V33z M17.9,35.2 l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 C18.2,34.7,18.2,35.1,17.9,35.2z M20.7,33.8l-0.1,0.1c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1 c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C20.7,33.2,20.8,33.5,20.7,33.8z M17.5,23.5c0,-3.6,2.9,-6.5,6.5,-6.5s6.5,2.9,6.5,6.5 c0,3.6,-2.9,6.5,-6.5,6.5S17.5,27.1,17.5,23.5z M27.4,35.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7 c0.3,-0.1,0.6,0,0.7,0.3l0,0.1C27.9,35.3,27.7,35.6,27.4,35.7z M29.7,32.7l-1.4,0.5c-0.2,0.1,-0.5,0,-0.5,-0.3l0,-0.1 c-0.1,-0.2,0,-0.5,0.3,-0.5l1.4,-0.5c0.2,-0.1,0.5,0,0.5,0.3l0,0.1C30,32.3,29.9,32.6,29.7,32.7z M32.8,35.5l-0.1,0.1 c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C32.8,34.9,32.9,35.2,32.8,35.5z M33.7,30.9c0,0.2,-0.2,0.4,-0.5,0.4l-0.1,0c-0.2,0,-0.4,-0.2,-0.4,-0.5l0.1,-1.5c0,-0.2,0.2,-0.4,0.5,-0.4l0.1,0c0.2,0,0.4,0.2,0.4,0.5 L33.7,30.9z M34.5,26.5l-1.3,0.9c-0.2,0.1,-0.5,0.1,-0.6,-0.1l-0.1,-0.1c-0.1,-0.2,-0.1,-0.5,0.1,-0.6l1.3,-0.9c0.2,-0.1,0.5,-0.1,0.6,0.1 l0.1,0.1C34.8,26.1,34.7,26.3,34.5,26.5z M35.6,20.6l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1 c0.3,0.1,0.4,0.5,0.2,0.8l-0.1,0.1C36.2,20.6,35.8,20.7,35.6,20.6z M38.6,27.1l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1L36.1,28 c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1C38.9,26.6,38.8,27,38.6,27.1z M39,19.4l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.5,0.4,-0.5l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1C39.4,19.1,39.2,19.3,39,19.4z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/food_sysuituna.xml b/packages/EasterEgg/res/drawable/food_sysuituna.xml deleted file mode 100644 index 28cf4a2c7683..000000000000 --- a/packages/EasterEgg/res/drawable/food_sysuituna.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- -Copyright (C) 2015 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:fillColor="#FF000000" - android:pathData="M46,18.4l-5.8,4.6c-3.9,-3.2,-8.9,-5.6,-14.6,-6.3l1.2,-6l-7.3,5.9C12.5,17.2,6.4,20,2,24.3l7.2,1.4L2,27 c4.3,4.2,10.4,7.1,17.3,7.6l3.1,2.5L22,34.8c7.1,0,13.5,-2.5,18.2,-6.5l5.8,4.6l-1.4,-7.2L46,18.4z M14.3,24.8l-0.6,0.6l-1.1,-1.1 l-1.1,1.1l-0.6,-0.6l1.1,-1.1l-1.1,-1.1l0.6,-0.6l1.1,1.1l1.1,-1.1l0.6,0.6l-1.1,1.1L14.3,24.8z M18.8,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8 c0,-1.6,-0.4,-3,-1.1,-3.8c1.1,0.5,1.9,2,1.9,3.8S19.9,28.5,18.8,29.1z M20.7,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8c0,-1.6,-0.4,-3,-1.1,-3.8 c1.1,0.5,1.9,2,1.9,3.8S21.8,28.5,20.7,29.1z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/foot1.xml b/packages/EasterEgg/res/drawable/foot1.xml deleted file mode 100644 index 0d9085998a18..000000000000 --- a/packages/EasterEgg/res/drawable/foot1.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="foot1" android:fillColor="#FF000000" android:pathData="M11.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/foot2.xml b/packages/EasterEgg/res/drawable/foot2.xml deleted file mode 100644 index 364ba0cd861c..000000000000 --- a/packages/EasterEgg/res/drawable/foot2.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="foot2" android:fillColor="#FF000000" android:pathData="M18.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/foot3.xml b/packages/EasterEgg/res/drawable/foot3.xml deleted file mode 100644 index e3a512a2568d..000000000000 --- a/packages/EasterEgg/res/drawable/foot3.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="foot3" android:fillColor="#FF000000" android:pathData="M29.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/foot4.xml b/packages/EasterEgg/res/drawable/foot4.xml deleted file mode 100644 index 66b78fa26649..000000000000 --- a/packages/EasterEgg/res/drawable/foot4.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="foot4" android:fillColor="#FF000000" android:pathData="M36.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/head.xml b/packages/EasterEgg/res/drawable/head.xml deleted file mode 100644 index df600a8613cd..000000000000 --- a/packages/EasterEgg/res/drawable/head.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="head" android:fillColor="#FF000000" android:pathData="M9,18.5c0,-8.3 6.8,-15 15,-15s15,6.7 15,15H9z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/bowtie.xml b/packages/EasterEgg/res/drawable/ic_clear.xml index 33fa9216712f..489dcd20759d 100644 --- a/packages/EasterEgg/res/drawable/bowtie.xml +++ b/packages/EasterEgg/res/drawable/ic_clear.xml @@ -1,5 +1,5 @@ <!-- -Copyright (C) 2016 The Android Open Source Project +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. @@ -14,9 +14,14 @@ Copyright (C) 2016 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="bowtie" android:fillColor="#FF000000" android:pathData="M29,16.8l-10,5l0,-5l10,5z"/> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19,6.41l-1.41,-1.41l-5.59,5.59l-5.59,-5.59l-1.41,1.41l5.59,5.59l-5.59,5.59l1.41,1.41l5.59,-5.59l5.59,5.59l1.41,-1.41l-5.59,-5.59z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> </vector> diff --git a/packages/EasterEgg/res/drawable/ic_dropper.xml b/packages/EasterEgg/res/drawable/ic_dropper.xml new file mode 100644 index 000000000000..230730921b9a --- /dev/null +++ b/packages/EasterEgg/res/drawable/ic_dropper.xml @@ -0,0 +1,39 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.6789,5.6997L3,16.3784L3,20L4,21L7.6216,21L18.3004,10.3212L13.6789,5.6997ZM7,19L5,19L5,17L13.788,8.344L15.6561,10.212L7,19Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M20.9983,2.4982L21.5018,3.0017C22.0876,3.5875 22.0876,4.5373 21.5018,5.1231L18.1231,8.5018C17.5373,9.0876 16.5875,9.0876 16.0017,8.5018L15.4982,7.9983C14.9124,7.4125 14.9124,6.4627 15.4982,5.8769L18.8769,2.4982C19.4627,1.9124 20.4125,1.9124 20.9983,2.4982Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.8284,3l7.0711,7.0711l-2.8284,2.8284l-7.0711,-7.0711z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> +</vector> diff --git a/packages/EasterEgg/res/drawable/ic_hourglass.xml b/packages/EasterEgg/res/drawable/ic_hourglass.xml new file mode 100644 index 000000000000..fe4b9c47e547 --- /dev/null +++ b/packages/EasterEgg/res/drawable/ic_hourglass.xml @@ -0,0 +1,27 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.5,11L16,7.5L16,4L8,4L8,7.5L11.5,11L11.5,13L8,16.5L8,20L16,20L16,16.5L12.5,13L12.5,11ZM6,2L18,2L18,8L17.99,8L18,8.01L14,12L18,16L17.99,16.01L18,16.01L18,22L6,22L6,16.01L6.01,16.01L6,16L10,12L6,8.01L6.01,8L6,8L6,2Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> +</vector> diff --git a/packages/EasterEgg/res/drawable/ic_share.xml b/packages/EasterEgg/res/drawable/ic_share.xml deleted file mode 100644 index 8cebc7ed46de..000000000000 --- a/packages/EasterEgg/res/drawable/ic_share.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- - Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M18.0,16.08c-0.76,0.0 -1.4,0.3 -1.9,0.77L8.91,12.7c0.05,-0.2 0.09,-0.4 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.5,0.5 1.2,0.81 2.0,0.81 1.66,0.0 3.0,-1.34 3.0,-3.0s-1.34,-3.0 -3.0,-3.0 -3.0,1.34 -3.0,3.0c0.0,0.2 0.0,0.4 0.0,0.7L8.04,9.81C7.5,9.31 6.79,9.0 6.0,9.0c-1.66,0.0 -3.0,1.34 -3.0,3.0s1.34,3.0 3.0,3.0c0.79,0.0 1.5,-0.31 2.04,-0.81l7.12,4.16c0.0,0.21 0.0,0.43 0.0,0.65 0.0,1.61 1.31,2.92 2.92,2.92 1.61,0.0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml index 5ce9e5133847..2306b7b554c5 100644 --- a/packages/EasterEgg/res/drawable/icon.xml +++ b/packages/EasterEgg/res/drawable/icon.xml @@ -1,7 +1,7 @@ <!-- -Copyright (C) 2017 The Android Open Source Project + Copyright (C) 2018 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); + 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 @@ -13,28 +13,7 @@ Copyright (C) 2017 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path - android:pathData="M25.0,25.0m-20.5,0.0a20.5,20.5,0,1,1,41.0,0.0a20.5,20.5,0,1,1,-41.0,0.0" - android:fillAlpha="0.066" - android:fillColor="#000000"/> - <path - android:pathData="M24.0,24.0m-20.0,0.0a20.0,20.0,0,1,1,40.0,0.0a20.0,20.0,0,1,1,-40.0,0.0" - android:fillColor="#283593"/> - <path - android:pathData="M44,24.2010101 L33.9004889,14.101499 L14.101499,33.9004889 L24.2010101,44 C29.2525804,43.9497929 34.2887564,41.9975027 38.1431296,38.1431296 C41.9975027,34.2887564 43.9497929,29.2525804 44,24.2010101 Z" - android:fillColor="#1a237e"/> - <path - android:pathData="M24.0,24.0m-14.0,0.0a14.0,14.0,0,1,1,28.0,0.0a14.0,14.0,0,1,1,-28.0,0.0" - android:fillColor="#5c6bc0"/> - <path - android:pathData="M37.7829445,26.469236 L29.6578482,18.3441397 L18.3441397,29.6578482 L26.469236,37.7829445 C29.1911841,37.2979273 31.7972024,36.0037754 33.9004889,33.9004889 C36.0037754,31.7972024 37.2979273,29.1911841 37.7829445,26.469236 Z" - android:fillColor="#3f51b5"/> - <path - android:pathData="M24.0,24.0m-8.0,0.0a8.0,8.0,0,1,1,16.0,0.0a8.0,8.0,0,1,1,-16.0,0.0" - android:fillColor="#FFFFFF"/> -</vector> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/icon_bg"/> + <foreground android:drawable="@drawable/p"/> +</adaptive-icon> diff --git a/packages/EasterEgg/res/xml/filepaths.xml b/packages/EasterEgg/res/drawable/icon_bg.xml index 2130025e9265..c1553ce50946 100644 --- a/packages/EasterEgg/res/xml/filepaths.xml +++ b/packages/EasterEgg/res/drawable/icon_bg.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2017 The Android Open Source Project + Copyright (C) 2018 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); + 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 @@ -14,6 +14,5 @@ Copyright (C) 2017 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<paths> - <external-path name="cats" path="Pictures/Cats" /> -</paths>
\ No newline at end of file +<color xmlns:android="http://schemas.android.com/apk/res/android" + android:color="#C5E1A5" />
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/left_ear.xml b/packages/EasterEgg/res/drawable/left_ear.xml deleted file mode 100644 index 2b98736df039..000000000000 --- a/packages/EasterEgg/res/drawable/left_ear.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="left_ear" android:fillColor="#FF000000" android:pathData="M15.4,1l5.1000004,5.3l-6.3,2.8000002z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/left_ear_inside.xml b/packages/EasterEgg/res/drawable/left_ear_inside.xml deleted file mode 100644 index 1d947edc31e2..000000000000 --- a/packages/EasterEgg/res/drawable/left_ear_inside.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="left_ear_inside" android:fillColor="#FF000000" android:pathData="M15.4,1l3.5,6.2l-4.7,1.9z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/left_eye.xml b/packages/EasterEgg/res/drawable/left_eye.xml deleted file mode 100644 index 4dde1b661393..000000000000 --- a/packages/EasterEgg/res/drawable/left_eye.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="left_eye" android:fillColor="#FF000000" android:pathData="M20.5,11c0,1.7 -3,1.7 -3,0C17.5,9.3 20.5,9.3 20.5,11z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/leg2.xml b/packages/EasterEgg/res/drawable/leg2.xml deleted file mode 100644 index a772a870af7d..000000000000 --- a/packages/EasterEgg/res/drawable/leg2.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="leg2" android:fillColor="#FF000000" android:pathData="M16,37h5v6h-5z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/leg2_shadow.xml b/packages/EasterEgg/res/drawable/leg2_shadow.xml deleted file mode 100644 index b01bd6995c0b..000000000000 --- a/packages/EasterEgg/res/drawable/leg2_shadow.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="leg2_shadow" android:fillColor="#FF000000" android:pathData="M16,37h5v3h-5z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/leg3.xml b/packages/EasterEgg/res/drawable/leg3.xml deleted file mode 100644 index d471236687b5..000000000000 --- a/packages/EasterEgg/res/drawable/leg3.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="leg3" android:fillColor="#FF000000" android:pathData="M27,37h5v6h-5z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/leg4.xml b/packages/EasterEgg/res/drawable/leg4.xml deleted file mode 100644 index e5868eb80c59..000000000000 --- a/packages/EasterEgg/res/drawable/leg4.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="leg4" android:fillColor="#FF000000" android:pathData="M34,37h5v6h-5z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/mouth.xml b/packages/EasterEgg/res/drawable/mouth.xml deleted file mode 100644 index ddcf2e82f976..000000000000 --- a/packages/EasterEgg/res/drawable/mouth.xml +++ /dev/null @@ -1,27 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="mouth" - android:strokeColor="#FF000000" - android:strokeWidth="1.2" - android:strokeLineCap="round" - android:pathData="M29,14.3c-0.4,0.8 -1.3,1.4 -2.3,1.4c-1.4,0 -2.7,-1.3 -2.7,-2.7 - M24,13c0,1.5 -1.2,2.7 -2.7,2.7c-1,0 -1.9,-0.5 -2.3,-1.4"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/nose.xml b/packages/EasterEgg/res/drawable/nose.xml deleted file mode 100644 index d403cd1baadf..000000000000 --- a/packages/EasterEgg/res/drawable/nose.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="nose" android:fillColor="#FF000000" android:pathData="M25.2,13c0,1.3 -2.3,1.3 -2.3,0S25.2,11.7 25.2,13z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/octo_bg.xml b/packages/EasterEgg/res/drawable/octo_bg.xml deleted file mode 100644 index 1e46cf434a8b..000000000000 --- a/packages/EasterEgg/res/drawable/octo_bg.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<shape xmlns:android="http://schemas.android.com/apk/res/android"> - <gradient android:angle="-90" - android:startColor="#FF205090" - android:endColor="#FF001040" - android:type="linear" - /> -</shape>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/p.xml b/packages/EasterEgg/res/drawable/p.xml new file mode 100644 index 000000000000..596b7824cdb7 --- /dev/null +++ b/packages/EasterEgg/res/drawable/p.xml @@ -0,0 +1,33 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:pathData="M49,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108" + android:strokeWidth="16" + android:fillColor="#00000000" + android:strokeColor="#7CB342" + android:fillType="evenOdd"/> + <path + android:pathData="M51,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108" + android:strokeWidth="8" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd"/> +</vector> diff --git a/packages/EasterEgg/res/drawable/right_ear.xml b/packages/EasterEgg/res/drawable/right_ear.xml deleted file mode 100644 index b9fb4d1c7470..000000000000 --- a/packages/EasterEgg/res/drawable/right_ear.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="right_ear" android:fillColor="#FF000000" android:pathData="M32.6,1l-5.0999985,5.3l6.299999,2.8000002z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/right_eye.xml b/packages/EasterEgg/res/drawable/right_eye.xml deleted file mode 100644 index a1871a62c25b..000000000000 --- a/packages/EasterEgg/res/drawable/right_eye.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="right_eye" android:fillColor="#FF000000" android:pathData="M30.5,11c0,1.7 -3,1.7 -3,0C27.5,9.3 30.5,9.3 30.5,11z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/stat_icon.xml b/packages/EasterEgg/res/drawable/stat_icon.xml deleted file mode 100644 index 608cb2017c3f..000000000000 --- a/packages/EasterEgg/res/drawable/stat_icon.xml +++ /dev/null @@ -1,30 +0,0 @@ -<!-- -Copyright (C) 2015 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#FF000000" - android:pathData="M12,2C6.5,2 2,6.5 2,12c0,5.5 4.5,10 10,10s10,-4.5 10,-10C22,6.5 17.5,2 12,2zM5.5,11c0,-1.6 3,-1.6 3,0C8.5,12.7 5.5,12.7 5.5,11zM17.5,14.6c-0.6,1 -1.7,1.7 -2.9,1.7c-1.1,0 -2,-0.6 -2.6,-1.4c-0.6,0.9 -1.6,1.4 -2.7,1.4c-1.3,0 -2.3,-0.7 -2.9,-1.8c-0.2,-0.3 0,-0.7 0.3,-0.8c0.3,-0.2 0.7,0 0.8,0.3c0.3,0.7 1,1.1 1.8,1.1c0.9,0 1.6,-0.5 1.9,-1.3c-0.2,-0.2 -0.4,-0.4 -0.4,-0.7c0,-1.3 2.3,-1.3 2.3,0c0,0.3 -0.2,0.6 -0.4,0.7c0.3,0.8 1.1,1.3 1.9,1.3c0.8,0 1.5,-0.6 1.8,-1.1c0.2,-0.3 0.6,-0.4 0.9,-0.2C17.6,13.9 17.7,14.3 17.5,14.6zM15.5,11c0,-1.6 3,-1.6 3,0C18.5,12.7 15.5,12.7 15.5,11z"/> - <path - android:fillColor="#FF000000" - android:pathData="M5.2,1.0l4.1000004,4.2l-5.0,2.1000004z"/> - <path - android:fillColor="#FF000000" - android:pathData="M18.8,1.0l-4.0999994,4.2l5.000001,2.1000004z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/tail.xml b/packages/EasterEgg/res/drawable/tail.xml deleted file mode 100644 index 0cca23c3e16c..000000000000 --- a/packages/EasterEgg/res/drawable/tail.xml +++ /dev/null @@ -1,26 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="tail" - android:strokeColor="#FF000000" - android:strokeWidth="5" - android:strokeLineCap="round" - android:pathData="M35,35.5h5.9c2.1,0 3.8,-1.7 3.8,-3.8v-6.2"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/tail_cap.xml b/packages/EasterEgg/res/drawable/tail_cap.xml deleted file mode 100644 index b82f6f9b478a..000000000000 --- a/packages/EasterEgg/res/drawable/tail_cap.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="tail_cap" android:fillColor="#FF000000" android:pathData="M42.2,25.5c0,-1.4 1.1,-2.5 2.5,-2.5s2.5,1.1 2.5,2.5H42.2z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/tail_shadow.xml b/packages/EasterEgg/res/drawable/tail_shadow.xml deleted file mode 100644 index bb1ff12b3afe..000000000000 --- a/packages/EasterEgg/res/drawable/tail_shadow.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright (C) 2016 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="tail_shadow" android:fillColor="#FF000000" android:pathData="M40,38l0,-5l-1,0l0,5z"/> -</vector> diff --git a/packages/EasterEgg/res/drawable/toolbar_bg.xml b/packages/EasterEgg/res/drawable/toolbar_bg.xml new file mode 100644 index 000000000000..0f0e702fd7c8 --- /dev/null +++ b/packages/EasterEgg/res/drawable/toolbar_bg.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + <solid android:color="@color/toolbar_bg_color" /> +</shape>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/ic_close.xml b/packages/EasterEgg/res/drawable/toolbar_button_bg.xml index 60ea36b11fcc..1b6a53ec7cc6 100644 --- a/packages/EasterEgg/res/drawable/ic_close.xml +++ b/packages/EasterEgg/res/drawable/toolbar_button_bg.xml @@ -1,5 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (C) 2016 The Android Open Source Project + 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. @@ -13,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/> -</vector> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?android:attr/colorControlHighlight"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/black" /> + <corners android:radius="4dp" /> + </shape> + </item> +</ripple> diff --git a/packages/EasterEgg/res/layout/activity_paint.xml b/packages/EasterEgg/res/layout/activity_paint.xml new file mode 100644 index 000000000000..a4c17afd1531 --- /dev/null +++ b/packages/EasterEgg/res/layout/activity_paint.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res/com.android.egg" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="#666" + tools:context=".paint.PaintActivity" + android:id="@+id/contentView" > + + <include layout="@layout/toolbar" + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="50dp" + android:layout_gravity="top" + /> + <include layout="@layout/colors" + android:id="@+id/colors" + android:layout_width="match_parent" + android:layout_height="48dp" + android:layout_gravity="top" + android:visibility="gone" + /> + <include layout="@layout/brushes" + android:id="@+id/brushes" + android:layout_width="match_parent" + android:layout_height="48dp" + android:layout_gravity="top" + android:visibility="gone" + /> + + +</FrameLayout>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/body.xml b/packages/EasterEgg/res/layout/brushes.xml index 86087209eff5..0c4b849b4eb8 100644 --- a/packages/EasterEgg/res/drawable/body.xml +++ b/packages/EasterEgg/res/layout/brushes.xml @@ -1,7 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2016 The Android Open Source Project + Copyright (C) 2018 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); + 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 @@ -13,10 +14,12 @@ Copyright (C) 2016 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> - <path android:name="body" android:fillColor="#FF000000" android:pathData="M9,20h30v18h-30z"/> -</vector> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="left" + android:background="@drawable/toolbar_bg" + android:elevation="10dp" + > +</LinearLayout>
\ No newline at end of file diff --git a/packages/EasterEgg/res/layout/cat_view.xml b/packages/EasterEgg/res/layout/cat_view.xml deleted file mode 100644 index 85b494d2e68d..000000000000 --- a/packages/EasterEgg/res/layout/cat_view.xml +++ /dev/null @@ -1,82 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2016 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. - --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeightSmall" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:background="?android:attr/selectableItemBackgroundBorderless" - android:gravity="center_horizontal" - android:clipToPadding="false"> - - <FrameLayout - android:layout_width="96dp" - android:layout_height="wrap_content"> - - <ImageView - android:id="@android:id/icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:padding="10dp" - android:layout_gravity="center" - android:scaleType="fitCenter" /> - - <LinearLayout - android:id="@+id/contextGroup" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:visibility="invisible" - android:layout_gravity="bottom"> - - <ImageView - android:id="@android:id/shareText" - android:layout_width="40dp" - android:layout_height="40dp" - android:padding="8dp" - android:src="@drawable/ic_share" - android:scaleType="fitCenter" - android:background="#40000000"/> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1" /> - - <ImageView - android:id="@android:id/closeButton" - android:layout_width="40dp" - android:layout_height="40dp" - android:padding="4dp" - android:src="@drawable/ic_close" - android:scaleType="fitCenter" - android:background="#40000000"/> - - </LinearLayout> - - </FrameLayout> - - <TextView - android:id="@android:id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceListItem" - android:gravity="center"/> -</LinearLayout> - diff --git a/packages/EasterEgg/res/drawable/right_ear_inside.xml b/packages/EasterEgg/res/layout/colors.xml index 86b6e3428d1f..b90f4d71b1e9 100644 --- a/packages/EasterEgg/res/drawable/right_ear_inside.xml +++ b/packages/EasterEgg/res/layout/colors.xml @@ -1,7 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2016 The Android Open Source Project + Copyright (C) 2018 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); + 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 @@ -13,11 +14,13 @@ Copyright (C) 2016 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48dp" - android:height="48dp" - android:viewportWidth="48.0" - android:viewportHeight="48.0"> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="left" + android:background="@drawable/toolbar_bg" + android:elevation="10dp" + > - <path android:name="right_ear_inside" android:fillColor="#FF000000" android:pathData="M33.8,9.1l-4.7,-1.9l3.5,-6.2z"/> -</vector> +</LinearLayout>
\ No newline at end of file diff --git a/packages/EasterEgg/res/layout/edit_text.xml b/packages/EasterEgg/res/layout/edit_text.xml deleted file mode 100644 index 9f7ac802bad4..000000000000 --- a/packages/EasterEgg/res/layout/edit_text.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2016 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. - --> - -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingStart="20dp" - android:paddingEnd="20dp"> - - <EditText - android:id="@android:id/edit" - android:maxLines="1" - android:layout_width="match_parent" - android:layout_height="wrap_content"/> - -</FrameLayout>
\ No newline at end of file diff --git a/packages/EasterEgg/res/layout/food_layout.xml b/packages/EasterEgg/res/layout/food_layout.xml deleted file mode 100644 index d0ca0c8899aa..000000000000 --- a/packages/EasterEgg/res/layout/food_layout.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2016 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. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="?android:attr/selectableItemBackgroundBorderless" - android:paddingLeft="4dp" android:paddingRight="4dp" - android:paddingBottom="6dp" android:paddingTop="6dp"> - <ImageView - android:layout_width="64dp" - android:layout_height="64dp" - android:id="@+id/icon" - android:tint="?android:attr/colorControlNormal"/> - <TextView android:layout_width="64dp" android:layout_height="wrap_content" - android:gravity="top|center_horizontal" - android:id="@+id/text" /> -</LinearLayout> diff --git a/packages/EasterEgg/res/layout/neko_activity.xml b/packages/EasterEgg/res/layout/neko_activity.xml deleted file mode 100644 index 21a4600bae40..000000000000 --- a/packages/EasterEgg/res/layout/neko_activity.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright (C) 2016 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. ---> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <android.support.v7.widget.RecyclerView - android:id="@+id/holder" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"/> -</FrameLayout>
\ No newline at end of file diff --git a/packages/EasterEgg/res/layout/toolbar.xml b/packages/EasterEgg/res/layout/toolbar.xml new file mode 100644 index 000000000000..9a5a9c541a4d --- /dev/null +++ b/packages/EasterEgg/res/layout/toolbar.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<com.android.egg.paint.CutoutAvoidingToolbar + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="50dp" + android:orientation="horizontal" + android:gravity="left" + android:background="@drawable/toolbar_bg" + android:elevation="20dp" + > + + <Space + android:tag="cutoutLeft" + android:layout_width="0dp" + android:layout_height="match_parent" + /> + + <LinearLayout + android:layout_width="0dp" + android:tag="beforeCutout" + android:layout_height="match_parent" + android:orientation="horizontal" + android:layout_weight="1" + tools:ignore="UselessParent"> + + <ImageButton + android:id="@+id/btnBrush" + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:tint="@color/toolbar_icon_color" + android:background="@drawable/toolbar_button_bg" + /> + + <ImageButton + android:id="@+id/btnColor" + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:tint="@color/toolbar_icon_color" + android:background="@drawable/toolbar_button_bg" + /> + + <ImageButton + android:id="@+id/btnSample" + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/toolbar_button_bg" + android:tint="@color/toolbar_icon_color" + android:src="@drawable/ic_dropper" /> + + </LinearLayout> + + <Space + android:tag="cutoutCenter" + android:layout_width="0dp" + android:layout_height="match_parent" + /> + + <LinearLayout + android:layout_width="0dp" + android:tag="afterCutout" + android:layout_height="match_parent" + android:orientation="horizontal" + android:layout_weight="1" + tools:ignore="UselessParent"> + + <ImageButton + android:id="@+id/btnZen" + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/toolbar_button_bg" + android:tint="@color/toolbar_icon_color" + android:src="@drawable/ic_hourglass" /> + + <ImageButton + android:id="@+id/btnClear" + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/toolbar_button_bg" + android:tint="@color/toolbar_icon_color" + android:src="@drawable/ic_clear" /> + + </LinearLayout> + + <Space + android:tag="cutoutRight" + android:layout_width="0dp" + android:layout_height="match_parent" + /> + +</com.android.egg.paint.CutoutAvoidingToolbar>
\ No newline at end of file diff --git a/packages/EasterEgg/res/values-night/colors.xml b/packages/EasterEgg/res/values-night/colors.xml new file mode 100644 index 000000000000..7c188f77f444 --- /dev/null +++ b/packages/EasterEgg/res/values-night/colors.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<resources> + <color name="toolbar_bg_color">#FF333333</color> + <color name="paper_color">#FF000000</color> + <color name="paint_color">#FFFFFFFF</color> +</resources>
\ No newline at end of file diff --git a/packages/EasterEgg/res/values-night/styles.xml b/packages/EasterEgg/res/values-night/styles.xml new file mode 100644 index 000000000000..4edf6926da41 --- /dev/null +++ b/packages/EasterEgg/res/values-night/styles.xml @@ -0,0 +1,21 @@ +<!-- + 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. +--> +<resources> + <style name="AppTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"> + <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> + <item name="android:windowLightNavigationBar">false</item> + </style> +</resources> diff --git a/packages/EasterEgg/res/values/attrs_toolbar_view.xml b/packages/EasterEgg/res/values/attrs_toolbar_view.xml new file mode 100644 index 000000000000..ed1360f7d468 --- /dev/null +++ b/packages/EasterEgg/res/values/attrs_toolbar_view.xml @@ -0,0 +1,19 @@ +<!-- + 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. +--> +<resources> + <declare-styleable name="ToolbarView"> + </declare-styleable> +</resources> diff --git a/packages/EasterEgg/res/values/colors.xml b/packages/EasterEgg/res/values/colors.xml new file mode 100644 index 000000000000..1a5388b738dd --- /dev/null +++ b/packages/EasterEgg/res/values/colors.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<resources> + <color name="toolbar_bg_color">#FFDDDDDD</color> + <color name="paper_color">#FFFFFFFF</color> + <color name="paint_color">#FF000000</color> +</resources>
\ No newline at end of file diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml index 61e38342872e..32dbc97a00fb 100644 --- a/packages/EasterEgg/res/values/strings.xml +++ b/packages/EasterEgg/res/values/strings.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright (C) 2016 The Android Open Source Project +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. @@ -15,40 +15,5 @@ Copyright (C) 2016 The Android Open Source Project limitations under the License. --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <string name="app_name" translatable="false">Android Easter Egg</string> - <string name="notification_name" translatable="false">Android Neko</string> - <string name="notification_channel_name" translatable="false">New cats</string> - <string name="default_tile_name" translatable="false">\????</string> - <string name="notification_title" translatable="false">A cat is here.</string> - <string name="default_cat_name" translatable="false">Cat #%s</string> - <string name="directory_name" translatable="false">Cats</string> - <string name="confirm_delete" translatable="false">Forget %s?</string> - <string-array name="food_names" translatable="false"> - <item>Empty dish</item> - <item>Bits</item> - <item>Fish</item> - <item>Chicken</item> - <item>Treat</item> - </string-array> - <array name="food_icons"> - <item>@drawable/food_dish</item> - <item>@drawable/food_bits</item> - <item>@drawable/food_sysuituna</item> - <item>@drawable/food_chicken</item> - <item>@drawable/food_cookie</item> - </array> - <integer-array name="food_intervals"> - <item>0</item> - <item>15</item> - <item>30</item> - <item>60</item> - <item>120</item> - </integer-array> - <integer-array name="food_new_cat_prob"> - <item>0</item> - <item>5</item> - <item>35</item> - <item>65</item> - <item>90</item> - </integer-array> + <string name="app_name" translatable="false">PAINT.APK</string> </resources> diff --git a/packages/EasterEgg/res/values/styles.xml b/packages/EasterEgg/res/values/styles.xml new file mode 100644 index 000000000000..44e2ce52aab8 --- /dev/null +++ b/packages/EasterEgg/res/values/styles.xml @@ -0,0 +1,23 @@ +<!-- + 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. +--> +<resources> + + <style name="AppTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"> + <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> + <item name="android:windowLightNavigationBar">true</item> + </style> + +</resources> diff --git a/packages/EasterEgg/src/com/android/egg/neko/Cat.java b/packages/EasterEgg/src/com/android/egg/neko/Cat.java deleted file mode 100644 index dd1bd07f3298..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/Cat.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.graphics.*; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; -import android.os.Bundle; - -import java.io.ByteArrayOutputStream; -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; - -import com.android.egg.R; -import com.android.internal.logging.MetricsLogger; - -import static com.android.egg.neko.NekoLand.CHAN_ID; - -public class Cat extends Drawable { - public static final long[] PURR = {0, 40, 20, 40, 20, 40, 20, 40, 20, 40, 20, 40}; - - private Random mNotSoRandom; - private Bitmap mBitmap; - private long mSeed; - private String mName; - private int mBodyColor; - private int mFootType; - private boolean mBowTie; - - private synchronized Random notSoRandom(long seed) { - if (mNotSoRandom == null) { - mNotSoRandom = new Random(); - mNotSoRandom.setSeed(seed); - } - return mNotSoRandom; - } - - public static final float frandrange(Random r, float a, float b) { - return (b-a)*r.nextFloat() + a; - } - - public static final Object choose(Random r, Object...l) { - return l[r.nextInt(l.length)]; - } - - public static final int chooseP(Random r, int[] a) { - int pct = r.nextInt(1000); - final int stop = a.length-2; - int i=0; - while (i<stop) { - pct -= a[i]; - if (pct < 0) break; - i+=2; - } - return a[i+1]; - } - - public static final int getColorIndex(int q, int[] a) { - for(int i = 1; i < a.length; i+=2) { - if (a[i] == q) { - return i/2; - } - } - return -1; - } - - public static final int[] P_BODY_COLORS = { - 180, 0xFF212121, // black - 180, 0xFFFFFFFF, // white - 140, 0xFF616161, // gray - 140, 0xFF795548, // brown - 100, 0xFF90A4AE, // steel - 100, 0xFFFFF9C4, // buff - 100, 0xFFFF8F00, // orange - 5, 0xFF29B6F6, // blue..? - 5, 0xFFFFCDD2, // pink!? - 5, 0xFFCE93D8, // purple?!?!? - 4, 0xFF43A047, // yeah, why not green - 1, 0, // ?!?!?! - }; - - public static final int[] P_COLLAR_COLORS = { - 250, 0xFFFFFFFF, - 250, 0xFF000000, - 250, 0xFFF44336, - 50, 0xFF1976D2, - 50, 0xFFFDD835, - 50, 0xFFFB8C00, - 50, 0xFFF48FB1, - 50, 0xFF4CAF50, - }; - - public static final int[] P_BELLY_COLORS = { - 750, 0, - 250, 0xFFFFFFFF, - }; - - public static final int[] P_DARK_SPOT_COLORS = { - 700, 0, - 250, 0xFF212121, - 50, 0xFF6D4C41, - }; - - public static final int[] P_LIGHT_SPOT_COLORS = { - 700, 0, - 300, 0xFFFFFFFF, - }; - - private CatParts D; - - public static void tint(int color, Drawable ... ds) { - for (Drawable d : ds) { - if (d != null) { - d.mutate().setTint(color); - } - } - } - - public static boolean isDark(int color) { - final int r = (color & 0xFF0000) >> 16; - final int g = (color & 0x00FF00) >> 8; - final int b = color & 0x0000FF; - return (r + g + b) < 0x80; - } - - public Cat(Context context, long seed) { - D = new CatParts(context); - mSeed = seed; - - setName(context.getString(R.string.default_cat_name, - String.valueOf(mSeed % 1000))); - - final Random nsr = notSoRandom(seed); - - // body color - mBodyColor = chooseP(nsr, P_BODY_COLORS); - if (mBodyColor == 0) mBodyColor = Color.HSVToColor(new float[] { - nsr.nextFloat()*360f, frandrange(nsr,0.5f,1f), frandrange(nsr,0.5f, 1f)}); - - tint(mBodyColor, D.body, D.head, D.leg1, D.leg2, D.leg3, D.leg4, D.tail, - D.leftEar, D.rightEar, D.foot1, D.foot2, D.foot3, D.foot4, D.tailCap); - tint(0x20000000, D.leg2Shadow, D.tailShadow); - if (isDark(mBodyColor)) { - tint(0xFFFFFFFF, D.leftEye, D.rightEye, D.mouth, D.nose); - } - tint(isDark(mBodyColor) ? 0xFFEF9A9A : 0x20D50000, D.leftEarInside, D.rightEarInside); - - tint(chooseP(nsr, P_BELLY_COLORS), D.belly); - tint(chooseP(nsr, P_BELLY_COLORS), D.back); - final int faceColor = chooseP(nsr, P_BELLY_COLORS); - tint(faceColor, D.faceSpot); - if (!isDark(faceColor)) { - tint(0xFF000000, D.mouth, D.nose); - } - - mFootType = 0; - if (nsr.nextFloat() < 0.25f) { - mFootType = 4; - tint(0xFFFFFFFF, D.foot1, D.foot2, D.foot3, D.foot4); - } else { - if (nsr.nextFloat() < 0.25f) { - mFootType = 2; - tint(0xFFFFFFFF, D.foot1, D.foot3); - } else if (nsr.nextFloat() < 0.25f) { - mFootType = 3; // maybe -2 would be better? meh. - tint(0xFFFFFFFF, D.foot2, D.foot4); - } else if (nsr.nextFloat() < 0.1f) { - mFootType = 1; - tint(0xFFFFFFFF, (Drawable) choose(nsr, D.foot1, D.foot2, D.foot3, D.foot4)); - } - } - - tint(nsr.nextFloat() < 0.333f ? 0xFFFFFFFF : mBodyColor, D.tailCap); - - final int capColor = chooseP(nsr, isDark(mBodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS); - tint(capColor, D.cap); - //tint(chooseP(nsr, isDark(bodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS), D.nose); - - final int collarColor = chooseP(nsr, P_COLLAR_COLORS); - tint(collarColor, D.collar); - mBowTie = nsr.nextFloat() < 0.1f; - tint(mBowTie ? collarColor : 0, D.bowtie); - } - - public static Cat create(Context context) { - return new Cat(context, Math.abs(ThreadLocalRandom.current().nextInt())); - } - - public Notification.Builder buildNotification(Context context) { - final Bundle extras = new Bundle(); - extras.putString("android.substName", context.getString(R.string.notification_name)); - final Intent intent = new Intent(Intent.ACTION_MAIN) - .setClass(context, NekoLand.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - return new Notification.Builder(context) - .setSmallIcon(Icon.createWithResource(context, R.drawable.stat_icon)) - .setLargeIcon(createNotificationLargeIcon(context)) - .setColor(getBodyColor()) - .setPriority(Notification.PRIORITY_LOW) - .setContentTitle(context.getString(R.string.notification_title)) - .setShowWhen(true) - .setCategory(Notification.CATEGORY_STATUS) - .setContentText(getName()) - .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0)) - .setAutoCancel(true) - .setChannel(CHAN_ID) - .setVibrate(PURR) - .addExtras(extras); - } - - public long getSeed() { - return mSeed; - } - - @Override - public void draw(Canvas canvas) { - final int w = Math.min(canvas.getWidth(), canvas.getHeight()); - final int h = w; - - if (mBitmap == null || mBitmap.getWidth() != w || mBitmap.getHeight() != h) { - mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - final Canvas bitCanvas = new Canvas(mBitmap); - slowDraw(bitCanvas, 0, 0, w, h); - } - canvas.drawBitmap(mBitmap, 0, 0, null); - } - - private void slowDraw(Canvas canvas, int x, int y, int w, int h) { - for (int i = 0; i < D.drawingOrder.length; i++) { - final Drawable d = D.drawingOrder[i]; - if (d != null) { - d.setBounds(x, y, x+w, y+h); - d.draw(canvas); - } - } - - } - - public Bitmap createBitmap(int w, int h) { - if (mBitmap != null && mBitmap.getWidth() == w && mBitmap.getHeight() == h) { - return mBitmap.copy(mBitmap.getConfig(), true); - } - Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - slowDraw(new Canvas(result), 0, 0, w, h); - return result; - } - - public static Icon recompressIcon(Icon bitmapIcon) { - if (bitmapIcon.getType() != Icon.TYPE_BITMAP) return bitmapIcon; - final Bitmap bits = bitmapIcon.getBitmap(); - final ByteArrayOutputStream ostream = new ByteArrayOutputStream( - bits.getWidth() * bits.getHeight() * 2); // guess 50% compression - final boolean ok = bits.compress(Bitmap.CompressFormat.PNG, 100, ostream); - if (!ok) return null; - return Icon.createWithData(ostream.toByteArray(), 0, ostream.size()); - } - - public Icon createNotificationLargeIcon(Context context) { - final Resources res = context.getResources(); - final int w = 2*res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width); - final int h = 2*res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height); - return recompressIcon(createIcon(context, w, h)); - } - - public Icon createIcon(Context context, int w, int h) { - Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(result); - final Paint pt = new Paint(); - float[] hsv = new float[3]; - Color.colorToHSV(mBodyColor, hsv); - hsv[2] = (hsv[2]>0.5f) - ? (hsv[2] - 0.25f) - : (hsv[2] + 0.25f); - pt.setColor(Color.HSVToColor(hsv)); - float r = w/2; - canvas.drawCircle(r, r, r, pt); - int m = w/10; - - slowDraw(canvas, m, m, w-m-m, h-m-m); - - return Icon.createWithBitmap(result); - } - - @Override - public void setAlpha(int i) { - - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - public String getName() { - return mName; - } - - public void setName(String name) { - this.mName = name; - } - - public int getBodyColor() { - return mBodyColor; - } - - public void logAdd(Context context) { - logCatAction(context, "egg_neko_add"); - } - - public void logRename(Context context) { - logCatAction(context, "egg_neko_rename"); - } - - public void logRemove(Context context) { - logCatAction(context, "egg_neko_remove"); - } - - public void logShare(Context context) { - logCatAction(context, "egg_neko_share"); - } - - private void logCatAction(Context context, String prefix) { - MetricsLogger.count(context, prefix, 1); - MetricsLogger.histogram(context, prefix +"_color", - getColorIndex(mBodyColor, P_BODY_COLORS)); - MetricsLogger.histogram(context, prefix + "_bowtie", mBowTie ? 1 : 0); - MetricsLogger.histogram(context, prefix + "_feet", mFootType); - } - - public static class CatParts { - public Drawable leftEar; - public Drawable rightEar; - public Drawable rightEarInside; - public Drawable leftEarInside; - public Drawable head; - public Drawable faceSpot; - public Drawable cap; - public Drawable mouth; - public Drawable body; - public Drawable foot1; - public Drawable leg1; - public Drawable foot2; - public Drawable leg2; - public Drawable foot3; - public Drawable leg3; - public Drawable foot4; - public Drawable leg4; - public Drawable tail; - public Drawable leg2Shadow; - public Drawable tailShadow; - public Drawable tailCap; - public Drawable belly; - public Drawable back; - public Drawable rightEye; - public Drawable leftEye; - public Drawable nose; - public Drawable bowtie; - public Drawable collar; - public Drawable[] drawingOrder; - - public CatParts(Context context) { - body = context.getDrawable(R.drawable.body); - head = context.getDrawable(R.drawable.head); - leg1 = context.getDrawable(R.drawable.leg1); - leg2 = context.getDrawable(R.drawable.leg2); - leg3 = context.getDrawable(R.drawable.leg3); - leg4 = context.getDrawable(R.drawable.leg4); - tail = context.getDrawable(R.drawable.tail); - leftEar = context.getDrawable(R.drawable.left_ear); - rightEar = context.getDrawable(R.drawable.right_ear); - rightEarInside = context.getDrawable(R.drawable.right_ear_inside); - leftEarInside = context.getDrawable(R.drawable.left_ear_inside); - faceSpot = context.getDrawable(R.drawable.face_spot); - cap = context.getDrawable(R.drawable.cap); - mouth = context.getDrawable(R.drawable.mouth); - foot4 = context.getDrawable(R.drawable.foot4); - foot3 = context.getDrawable(R.drawable.foot3); - foot1 = context.getDrawable(R.drawable.foot1); - foot2 = context.getDrawable(R.drawable.foot2); - leg2Shadow = context.getDrawable(R.drawable.leg2_shadow); - tailShadow = context.getDrawable(R.drawable.tail_shadow); - tailCap = context.getDrawable(R.drawable.tail_cap); - belly = context.getDrawable(R.drawable.belly); - back = context.getDrawable(R.drawable.back); - rightEye = context.getDrawable(R.drawable.right_eye); - leftEye = context.getDrawable(R.drawable.left_eye); - nose = context.getDrawable(R.drawable.nose); - collar = context.getDrawable(R.drawable.collar); - bowtie = context.getDrawable(R.drawable.bowtie); - drawingOrder = getDrawingOrder(); - } - private Drawable[] getDrawingOrder() { - return new Drawable[] { - collar, - leftEar, leftEarInside, rightEar, rightEarInside, - head, - faceSpot, - cap, - leftEye, rightEye, - nose, mouth, - tail, tailCap, tailShadow, - foot1, leg1, - foot2, leg2, - foot3, leg3, - foot4, leg4, - leg2Shadow, - body, belly, - bowtie - }; - } - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/Food.java b/packages/EasterEgg/src/com/android/egg/neko/Food.java deleted file mode 100644 index 5c0f12e2639f..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/Food.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; - -import com.android.egg.R; - -public class Food { - private final int mType; - - private static int[] sIcons; - private static String[] sNames; - - public Food(int type) { - mType = type; - } - - public Icon getIcon(Context context) { - if (sIcons == null) { - TypedArray icons = context.getResources().obtainTypedArray(R.array.food_icons); - sIcons = new int[icons.length()]; - for (int i = 0; i < sIcons.length; i++) { - sIcons[i] = icons.getResourceId(i, 0); - } - icons.recycle(); - } - return Icon.createWithResource(context, sIcons[mType]); - } - - public String getName(Context context) { - if (sNames == null) { - sNames = context.getResources().getStringArray(R.array.food_names); - } - return sNames[mType]; - } - - public long getInterval(Context context) { - return context.getResources().getIntArray(R.array.food_intervals)[mType]; - } - - public int getType() { - return mType; - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java deleted file mode 100644 index c0b725c05899..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.pm.PackageManager; -import android.util.Log; -import android.widget.Toast; - -import com.android.internal.logging.MetricsLogger; - -public class NekoActivationActivity extends Activity { - private void toastUp(String s) { - Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT); - toast.getView().setBackgroundDrawable(null); - toast.show(); - } - - @Override - public void onStart() { - super.onStart(); - - final PackageManager pm = getPackageManager(); - final ComponentName cn = new ComponentName(this, NekoTile.class); - if (pm.getComponentEnabledSetting(cn) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - if (NekoLand.DEBUG) { - Log.v("Neko", "Disabling tile."); - } - pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - MetricsLogger.histogram(this, "egg_neko_enable", 0); - toastUp("\uD83D\uDEAB"); - } else { - if (NekoLand.DEBUG) { - Log.v("Neko", "Enabling tile."); - } - pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP); - MetricsLogger.histogram(this, "egg_neko_enable", 1); - toastUp("\uD83D\uDC31"); - } - finish(); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java b/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java deleted file mode 100644 index 2d2fbe8207af..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.support.annotation.NonNull; -import android.app.Dialog; -import android.content.Context; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.egg.R; -import com.android.internal.logging.MetricsLogger; - -import java.util.ArrayList; - -public class NekoDialog extends Dialog { - - private final Adapter mAdapter; - - public NekoDialog(@NonNull Context context) { - super(context, android.R.style.Theme_Material_Dialog_NoActionBar); - RecyclerView view = new RecyclerView(getContext()); - mAdapter = new Adapter(getContext()); - view.setLayoutManager(new GridLayoutManager(getContext(), 2)); - view.setAdapter(mAdapter); - final float dp = context.getResources().getDisplayMetrics().density; - final int pad = (int)(16*dp); - view.setPadding(pad, pad, pad, pad); - setContentView(view); - } - - private void onFoodSelected(Food food) { - PrefState prefs = new PrefState(getContext()); - int currentState = prefs.getFoodState(); - if (currentState == 0 && food.getType() != 0) { - NekoService.registerJob(getContext(), food.getInterval(getContext())); - } - MetricsLogger.histogram(getContext(), "egg_neko_offered_food", food.getType()); - prefs.setFoodState(food.getType()); - dismiss(); - } - - private class Adapter extends RecyclerView.Adapter<Holder> { - - private final Context mContext; - private final ArrayList<Food> mFoods = new ArrayList<>(); - - public Adapter(Context context) { - mContext = context; - int[] foods = context.getResources().getIntArray(R.array.food_names); - // skip food 0, you can't choose it - for (int i=1; i<foods.length; i++) { - mFoods.add(new Food(i)); - } - } - - @Override - public Holder onCreateViewHolder(ViewGroup parent, int viewType) { - return new Holder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.food_layout, parent, false)); - } - - @Override - public void onBindViewHolder(final Holder holder, int position) { - final Food food = mFoods.get(position); - ((ImageView) holder.itemView.findViewById(R.id.icon)) - .setImageIcon(food.getIcon(mContext)); - ((TextView) holder.itemView.findViewById(R.id.text)) - .setText(food.getName(mContext)); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onFoodSelected(mFoods.get(holder.getAdapterPosition())); - } - }); - } - - @Override - public int getItemCount() { - return mFoods.size(); - } - } - - public static class Holder extends RecyclerView.ViewHolder { - - public Holder(View itemView) { - super(itemView); - } - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java deleted file mode 100644 index d2e37d8779d1..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.Manifest; -import android.app.ActionBar; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.media.MediaScannerConnection; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.provider.MediaStore.Images; -import android.support.v4.content.FileProvider; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.view.ContextThemeWrapper; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnLongClickListener; -import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.egg.R; -import com.android.egg.neko.PrefState.PrefsListener; -import com.android.internal.logging.MetricsLogger; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class NekoLand extends Activity implements PrefsListener { - public static String CHAN_ID = "EGG"; - - public static boolean DEBUG = false; - public static boolean DEBUG_NOTIFICATIONS = false; - - private static final int EXPORT_BITMAP_SIZE = 600; - - private static final int STORAGE_PERM_REQUEST = 123; - - private static boolean CAT_GEN = false; - private PrefState mPrefs; - private CatAdapter mAdapter; - private Cat mPendingShareCat; - - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.neko_activity); - final ActionBar actionBar = getActionBar(); - if (actionBar != null) { - actionBar.setLogo(Cat.create(this)); - actionBar.setDisplayUseLogoEnabled(false); - actionBar.setDisplayShowHomeEnabled(true); - } - - mPrefs = new PrefState(this); - mPrefs.setListener(this); - final RecyclerView recyclerView = findViewById(R.id.holder); - mAdapter = new CatAdapter(); - recyclerView.setAdapter(mAdapter); - recyclerView.setLayoutManager(new GridLayoutManager(this, 3)); - int numCats = updateCats(); - MetricsLogger.histogram(this, "egg_neko_visit_gallery", numCats); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mPrefs.setListener(null); - } - - private int updateCats() { - Cat[] cats; - if (CAT_GEN) { - cats = new Cat[50]; - for (int i = 0; i < cats.length; i++) { - cats[i] = Cat.create(this); - } - } else { - final float[] hsv = new float[3]; - List<Cat> list = mPrefs.getCats(); - Collections.sort(list, new Comparator<Cat>() { - @Override - public int compare(Cat cat, Cat cat2) { - Color.colorToHSV(cat.getBodyColor(), hsv); - float bodyH1 = hsv[0]; - Color.colorToHSV(cat2.getBodyColor(), hsv); - float bodyH2 = hsv[0]; - return Float.compare(bodyH1, bodyH2); - } - }); - cats = list.toArray(new Cat[0]); - } - mAdapter.setCats(cats); - return cats.length; - } - - private void onCatClick(Cat cat) { - if (CAT_GEN) { - mPrefs.addCat(cat); - new AlertDialog.Builder(NekoLand.this) - .setTitle("Cat added") - .setPositiveButton(android.R.string.ok, null) - .show(); - } else { - showNameDialog(cat); - } -// noman.notify(1, cat.buildNotification(NekoLand.this).build()); - } - - private void onCatRemove(Cat cat) { - cat.logRemove(this); - mPrefs.removeCat(cat); - } - - private void showNameDialog(final Cat cat) { - final Context context = new ContextThemeWrapper(this, - android.R.style.Theme_Material_Light_Dialog_NoActionBar); - // TODO: Move to XML, add correct margins. - View view = LayoutInflater.from(context).inflate(R.layout.edit_text, null); - final EditText text = (EditText) view.findViewById(android.R.id.edit); - text.setText(cat.getName()); - text.setSelection(cat.getName().length()); - final int size = context.getResources() - .getDimensionPixelSize(android.R.dimen.app_icon_size); - Drawable catIcon = cat.createIcon(this, size, size).loadDrawable(this); - new AlertDialog.Builder(context) - .setTitle(" ") - .setIcon(catIcon) - .setView(view) - .setPositiveButton(android.R.string.ok, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - cat.logRename(context); - cat.setName(text.getText().toString().trim()); - mPrefs.addCat(cat); - } - }).show(); - } - - @Override - public void onPrefsChanged() { - updateCats(); - } - - private class CatAdapter extends RecyclerView.Adapter<CatHolder> { - - private Cat[] mCats; - - public void setCats(Cat[] cats) { - mCats = cats; - notifyDataSetChanged(); - } - - @Override - public CatHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new CatHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.cat_view, parent, false)); - } - - private void setContextGroupVisible(final CatHolder holder, boolean vis) { - final View group = holder.contextGroup; - if (vis && group.getVisibility() != View.VISIBLE) { - group.setAlpha(0); - group.setVisibility(View.VISIBLE); - group.animate().alpha(1.0f).setDuration(333); - Runnable hideAction = new Runnable() { - @Override - public void run() { - setContextGroupVisible(holder, false); - } - }; - group.setTag(hideAction); - group.postDelayed(hideAction, 5000); - } else if (!vis && group.getVisibility() == View.VISIBLE) { - group.removeCallbacks((Runnable) group.getTag()); - group.animate().alpha(0f).setDuration(250).withEndAction(new Runnable() { - @Override - public void run() { - group.setVisibility(View.INVISIBLE); - } - }); - } - } - - @Override - public void onBindViewHolder(final CatHolder holder, int position) { - Context context = holder.itemView.getContext(); - final int size = context.getResources().getDimensionPixelSize(R.dimen.neko_display_size); - holder.imageView.setImageIcon(mCats[position].createIcon(context, size, size)); - holder.textView.setText(mCats[position].getName()); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onCatClick(mCats[holder.getAdapterPosition()]); - } - }); - holder.itemView.setOnLongClickListener(new OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - setContextGroupVisible(holder, true); - return true; - } - }); - holder.delete.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setContextGroupVisible(holder, false); - new AlertDialog.Builder(NekoLand.this) - .setTitle(getString(R.string.confirm_delete, mCats[position].getName())) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - onCatRemove(mCats[holder.getAdapterPosition()]); - } - }) - .show(); - } - }); - holder.share.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setContextGroupVisible(holder, false); - Cat cat = mCats[holder.getAdapterPosition()]; - if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - mPendingShareCat = cat; - requestPermissions( - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - STORAGE_PERM_REQUEST); - return; - } - shareCat(cat); - } - }); - } - - @Override - public int getItemCount() { - return mCats.length; - } - } - - private void shareCat(Cat cat) { - final File dir = new File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), - getString(R.string.directory_name)); - if (!dir.exists() && !dir.mkdirs()) { - Log.e("NekoLand", "save: error: can't create Pictures directory"); - return; - } - final File png = new File(dir, cat.getName().replaceAll("[/ #:]+", "_") + ".png"); - Bitmap bitmap = cat.createBitmap(EXPORT_BITMAP_SIZE, EXPORT_BITMAP_SIZE); - if (bitmap != null) { - try { - OutputStream os = new FileOutputStream(png); - bitmap.compress(Bitmap.CompressFormat.PNG, 0, os); - os.close(); - MediaScannerConnection.scanFile( - this, - new String[] {png.toString()}, - new String[] {"image/png"}, - null); - Log.v("Neko", "cat file: " + png); - Uri uri = FileProvider.getUriForFile(this, "com.android.egg.fileprovider", png); - Log.v("Neko", "cat uri: " + uri); - Intent intent = new Intent(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_STREAM, uri); - intent.putExtra(Intent.EXTRA_SUBJECT, cat.getName()); - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - intent.setType("image/png"); - startActivity(Intent.createChooser(intent, null)); - cat.logShare(this); - } catch (IOException e) { - Log.e("NekoLand", "save: error: " + e); - } - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, - String permissions[], int[] grantResults) { - if (requestCode == STORAGE_PERM_REQUEST) { - if (mPendingShareCat != null) { - shareCat(mPendingShareCat); - mPendingShareCat = null; - } - } - } - - private static class CatHolder extends RecyclerView.ViewHolder { - private final ImageView imageView; - private final TextView textView; - private final View contextGroup; - private final View delete; - private final View share; - - public CatHolder(View itemView) { - super(itemView); - imageView = (ImageView) itemView.findViewById(android.R.id.icon); - textView = (TextView) itemView.findViewById(android.R.id.title); - contextGroup = itemView.findViewById(R.id.contextGroup); - delete = itemView.findViewById(android.R.id.closeButton); - share = itemView.findViewById(android.R.id.shareText); - } - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java deleted file mode 100644 index 5f01da879ebb..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.support.annotation.Nullable; -import android.app.Activity; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; -import android.os.Bundle; -import android.view.WindowManager; - -public class NekoLockedActivity extends Activity implements OnDismissListener { - - private NekoDialog mDialog; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - - mDialog = new NekoDialog(this); - mDialog.setOnDismissListener(this); - mDialog.show(); - } - - @Override - public void onDismiss(DialogInterface dialog) { - finish(); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java deleted file mode 100644 index 42506e61d2ec..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.job.JobInfo; -import android.app.job.JobParameters; -import android.app.job.JobScheduler; -import android.app.job.JobService; -import android.content.ComponentName; -import android.content.Context; -import android.net.Uri; -import android.os.Bundle; - -import java.util.List; -import android.util.Log; - -import com.android.egg.R; - -import java.util.Random; - -import static com.android.egg.neko.Cat.PURR; -import static com.android.egg.neko.NekoLand.CHAN_ID; - -public class NekoService extends JobService { - - private static final String TAG = "NekoService"; - - public static int JOB_ID = 42; - - public static int CAT_NOTIFICATION = 1; - public static int DEBUG_NOTIFICATION = 1234; - - public static float CAT_CAPTURE_PROB = 1.0f; // generous - - public static long SECONDS = 1000; - public static long MINUTES = 60 * SECONDS; - - public static long INTERVAL_FLEX = 5 * MINUTES; - - public static float INTERVAL_JITTER_FRAC = 0.25f; - - private static void setupNotificationChannels(Context context) { - NotificationManager noman = context.getSystemService(NotificationManager.class); - NotificationChannel eggChan = new NotificationChannel(CHAN_ID, - context.getString(R.string.notification_channel_name), - NotificationManager.IMPORTANCE_DEFAULT); - eggChan.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT); // cats are quiet - eggChan.setVibrationPattern(PURR); // not totally quiet though - eggChan.setBlockableSystem(true); // unlike a real cat, you can push this one off your lap - eggChan.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); // cats sit in the window - noman.createNotificationChannel(eggChan); - } - - @Override - public boolean onStartJob(JobParameters params) { - Log.v(TAG, "Starting job: " + String.valueOf(params)); - - NotificationManager noman = getSystemService(NotificationManager.class); - if (NekoLand.DEBUG_NOTIFICATIONS) { - final Bundle extras = new Bundle(); - extras.putString("android.substName", getString(R.string.notification_name)); - final int size = getResources() - .getDimensionPixelSize(android.R.dimen.notification_large_icon_width); - final Cat cat = Cat.create(this); - final Notification.Builder builder - = cat.buildNotification(this) - .setContentTitle("DEBUG") - .setChannel(NekoLand.CHAN_ID) - .setContentText("Ran job: " + params); - noman.notify(DEBUG_NOTIFICATION, builder.build()); - } - - final PrefState prefs = new PrefState(this); - int food = prefs.getFoodState(); - if (food != 0) { - prefs.setFoodState(0); // nom - final Random rng = new Random(); - if (rng.nextFloat() <= CAT_CAPTURE_PROB) { - Cat cat; - List<Cat> cats = prefs.getCats(); - final int[] probs = getResources().getIntArray(R.array.food_new_cat_prob); - final float new_cat_prob = (float)((food < probs.length) ? probs[food] : 50) / 100f; - - if (cats.size() == 0 || rng.nextFloat() <= new_cat_prob) { - cat = Cat.create(this); - prefs.addCat(cat); - cat.logAdd(this); - Log.v(TAG, "A new cat is here: " + cat.getName()); - } else { - cat = cats.get(rng.nextInt(cats.size())); - Log.v(TAG, "A cat has returned: " + cat.getName()); - } - - final Notification.Builder builder = cat.buildNotification(this); - noman.notify(CAT_NOTIFICATION, builder.build()); - } - } - cancelJob(this); - return false; - } - - @Override - public boolean onStopJob(JobParameters jobParameters) { - return false; - } - - public static void registerJobIfNeeded(Context context, long intervalMinutes) { - JobScheduler jss = context.getSystemService(JobScheduler.class); - JobInfo info = jss.getPendingJob(JOB_ID); - if (info == null) { - registerJob(context, intervalMinutes); - } - } - - public static void registerJob(Context context, long intervalMinutes) { - setupNotificationChannels(context); - - JobScheduler jss = context.getSystemService(JobScheduler.class); - jss.cancel(JOB_ID); - long interval = intervalMinutes * MINUTES; - long jitter = (long)(INTERVAL_JITTER_FRAC * interval); - interval += (long)(Math.random() * (2 * jitter)) - jitter; - final JobInfo jobInfo = new JobInfo.Builder(JOB_ID, - new ComponentName(context, NekoService.class)) - .setPeriodic(interval, INTERVAL_FLEX) - .build(); - - Log.v(TAG, "A cat will visit in " + interval + "ms: " + String.valueOf(jobInfo)); - jss.schedule(jobInfo); - - if (NekoLand.DEBUG_NOTIFICATIONS) { - NotificationManager noman = context.getSystemService(NotificationManager.class); - noman.notify(DEBUG_NOTIFICATION, new Notification.Builder(context) - .setSmallIcon(R.drawable.stat_icon) - .setContentTitle(String.format("Job scheduled in %d min", (interval / MINUTES))) - .setContentText(String.valueOf(jobInfo)) - .setPriority(Notification.PRIORITY_MIN) - .setCategory(Notification.CATEGORY_SERVICE) - .setChannel(NekoLand.CHAN_ID) - .setShowWhen(true) - .build()); - } - } - - public static void cancelJob(Context context) { - JobScheduler jss = context.getSystemService(JobScheduler.class); - Log.v(TAG, "Canceling job"); - jss.cancel(JOB_ID); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java deleted file mode 100644 index 159b40a3e5af..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.content.Intent; -import android.service.quicksettings.Tile; -import android.service.quicksettings.TileService; -import android.util.Log; - -import com.android.egg.neko.PrefState.PrefsListener; -import com.android.internal.logging.MetricsLogger; - -public class NekoTile extends TileService implements PrefsListener { - - private static final String TAG = "NekoTile"; - - private PrefState mPrefs; - - @Override - public void onCreate() { - super.onCreate(); - mPrefs = new PrefState(this); - } - - @Override - public void onStartListening() { - super.onStartListening(); - mPrefs.setListener(this); - updateState(); - } - - @Override - public void onStopListening() { - super.onStopListening(); - mPrefs.setListener(null); - } - - @Override - public void onTileAdded() { - super.onTileAdded(); - MetricsLogger.count(this, "egg_neko_tile_added", 1); - } - - @Override - public void onTileRemoved() { - super.onTileRemoved(); - MetricsLogger.count(this, "egg_neko_tile_removed", 1); - } - - @Override - public void onPrefsChanged() { - updateState(); - } - - private void updateState() { - Tile tile = getQsTile(); - int foodState = mPrefs.getFoodState(); - Food food = new Food(foodState); - if (foodState != 0) { - NekoService.registerJobIfNeeded(this, food.getInterval(this)); - } - tile.setIcon(food.getIcon(this)); - tile.setLabel(food.getName(this)); - tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); - tile.updateTile(); - } - - @Override - public void onClick() { - if (mPrefs.getFoodState() != 0) { - // there's already food loaded, let's empty it - MetricsLogger.count(this, "egg_neko_empty_food", 1); - mPrefs.setFoodState(0); - NekoService.cancelJob(this); - } else { - // time to feed the cats - if (isLocked()) { - if (isSecure()) { - Log.d(TAG, "startActivityAndCollapse"); - Intent intent = new Intent(this, NekoLockedActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivityAndCollapse(intent); - } else { - unlockAndRun(new Runnable() { - @Override - public void run() { - showNekoDialog(); - } - }); - } - } else { - showNekoDialog(); - } - } - } - - private void showNekoDialog() { - Log.d(TAG, "showNekoDialog"); - MetricsLogger.count(this, "egg_neko_select_food", 1); - showDialog(new NekoDialog(this)); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java deleted file mode 100644 index bf71b197d3cb..000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class PrefState implements OnSharedPreferenceChangeListener { - - private static final String FILE_NAME = "mPrefs"; - - private static final String FOOD_STATE = "food"; - - private static final String CAT_KEY_PREFIX = "cat:"; - - private final Context mContext; - private final SharedPreferences mPrefs; - private PrefsListener mListener; - - public PrefState(Context context) { - mContext = context; - mPrefs = mContext.getSharedPreferences(FILE_NAME, 0); - } - - // Can also be used for renaming. - public void addCat(Cat cat) { - mPrefs.edit() - .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName()) - .apply(); - } - - public void removeCat(Cat cat) { - mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply(); - } - - public List<Cat> getCats() { - ArrayList<Cat> cats = new ArrayList<>(); - Map<String, ?> map = mPrefs.getAll(); - for (String key : map.keySet()) { - if (key.startsWith(CAT_KEY_PREFIX)) { - long seed = Long.parseLong(key.substring(CAT_KEY_PREFIX.length())); - Cat cat = new Cat(mContext, seed); - cat.setName(String.valueOf(map.get(key))); - cats.add(cat); - } - } - return cats; - } - - public int getFoodState() { - return mPrefs.getInt(FOOD_STATE, 0); - } - - public void setFoodState(int foodState) { - mPrefs.edit().putInt(FOOD_STATE, foodState).apply(); - } - - public void setListener(PrefsListener listener) { - mListener = listener; - if (mListener != null) { - mPrefs.registerOnSharedPreferenceChangeListener(this); - } else { - mPrefs.unregisterOnSharedPreferenceChangeListener(this); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - mListener.onPrefsChanged(); - } - - public interface PrefsListener { - void onPrefsChanged(); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java b/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java deleted file mode 100644 index 8a06cc604f1e..000000000000 --- a/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2017 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.egg.octo; - -import android.app.Activity; -import android.os.Bundle; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; - -import com.android.egg.R; - -public class Ocquarium extends Activity { - ImageView mImageView; - private OctopusDrawable mOcto; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final float dp = getResources().getDisplayMetrics().density; - - getWindow().setBackgroundDrawableResource(R.drawable.octo_bg); - - FrameLayout bg = new FrameLayout(this); - setContentView(bg); - bg.setAlpha(0f); - bg.animate().setStartDelay(500).setDuration(5000).alpha(1f).start(); - - mImageView = new ImageView(this); - bg.addView(mImageView, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - - mOcto = new OctopusDrawable(getApplicationContext()); - mOcto.setSizePx((int) (OctopusDrawable.randfrange(40f,180f) * dp)); - mImageView.setImageDrawable(mOcto); - - mImageView.setOnTouchListener(new View.OnTouchListener() { - boolean touching; - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - switch (motionEvent.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - if (mOcto.hitTest(motionEvent.getX(), motionEvent.getY())) { - touching = true; - mOcto.stopDrift(); - } - break; - case MotionEvent.ACTION_MOVE: - if (touching) { - mOcto.moveTo(motionEvent.getX(), motionEvent.getY()); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - touching = false; - mOcto.startDrift(); - break; - } - return true; - } - }); - } - - @Override - protected void onPause() { - mOcto.stopDrift(); - super.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - mOcto.startDrift(); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java b/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java deleted file mode 100644 index 5dde6e115268..000000000000 --- a/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (C) 2017 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.egg.octo; - -import android.animation.TimeAnimator; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.DashPathEffect; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PixelFormat; -import android.graphics.PointF; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.support.animation.DynamicAnimation; -import android.support.animation.SpringForce; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.animation.SpringAnimation; -import android.support.animation.FloatValueHolder; - -public class OctopusDrawable extends Drawable { - private static float BASE_SCALE = 100f; - public static boolean PATH_DEBUG = false; - - private static int BODY_COLOR = 0xFF101010; - private static int ARM_COLOR = 0xFF101010; - private static int ARM_COLOR_BACK = 0xFF000000; - private static int EYE_COLOR = 0xFF808080; - - private static int[] BACK_ARMS = {1, 3, 4, 6}; - private static int[] FRONT_ARMS = {0, 2, 5, 7}; - - private Paint mPaint = new Paint(); - private Arm[] mArms = new Arm[8]; - final PointF point = new PointF(); - private int mSizePx = 100; - final Matrix M = new Matrix(); - final Matrix M_inv = new Matrix(); - private TimeAnimator mDriftAnimation; - private boolean mBlinking; - private float[] ptmp = new float[2]; - private float[] scaledBounds = new float[2]; - - public static float randfrange(float a, float b) { - return (float) (Math.random()*(b-a) + a); - } - public static float clamp(float v, float a, float b) { - return v<a?a:v>b?b:v; - } - - public OctopusDrawable(Context context) { - float dp = context.getResources().getDisplayMetrics().density; - setSizePx((int) (100*dp)); - mPaint.setAntiAlias(true); - for (int i=0; i<mArms.length; i++) { - final float bias = (float)i/(mArms.length-1) - 0.5f; - mArms[i] = new Arm( - 0,0, // arm will be repositioned on moveTo - 10f*bias + randfrange(0,20f), randfrange(20f,50f), - 40f*bias+randfrange(-60f,60f), randfrange(30f, 80f), - randfrange(-40f,40f), randfrange(-80f,40f), - 14f, 2f); - } - } - - public void setSizePx(int size) { - mSizePx = size; - M.setScale(mSizePx/BASE_SCALE, mSizePx/BASE_SCALE); - // TaperedPathStroke.setMinStep(20f*BASE_SCALE/mSizePx); // nice little floaty circles - TaperedPathStroke.setMinStep(8f*BASE_SCALE/mSizePx); // classic tentacles - M.invert(M_inv); - } - - public void startDrift() { - if (mDriftAnimation == null) { - mDriftAnimation = new TimeAnimator(); - mDriftAnimation.setTimeListener(new TimeAnimator.TimeListener() { - float MAX_VY = 35f; - float JUMP_VY = -100f; - float MAX_VX = 15f; - private float ax = 0f, ay = 30f; - private float vx, vy; - long nextjump = 0; - long unblink = 0; - @Override - public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) { - float t_sec = 0.001f * t; - float dt_sec = 0.001f * dt; - if (t > nextjump) { - vy = JUMP_VY; - nextjump = t + (long) randfrange(5000, 10000); - } - if (unblink > 0 && t > unblink) { - setBlinking(false); - unblink = 0; - } else if (Math.random() < 0.001f) { - setBlinking(true); - unblink = t + 200; - } - - ax = (float) (MAX_VX * Math.sin(t_sec*.25f)); - - vx = clamp(vx + dt_sec * ax, -MAX_VX, MAX_VX); - vy = clamp(vy + dt_sec * ay, -100*MAX_VY, MAX_VY); - - // oob check - if (point.y - BASE_SCALE/2 > scaledBounds[1]) { - vy = JUMP_VY; - } else if (point.y + BASE_SCALE < 0) { - vy = MAX_VY; - } - - point.x = clamp(point.x + dt_sec * vx, 0, scaledBounds[0]); - point.y = point.y + dt_sec * vy; - - repositionArms(); - } - }); - } - mDriftAnimation.start(); - } - - public void stopDrift() { - mDriftAnimation.cancel(); - } - - @Override - public void onBoundsChange(Rect bounds) { - final float w = bounds.width(); - final float h = bounds.height(); - - lockArms(true); - moveTo(w/2, h/2); - lockArms(false); - - scaledBounds[0] = w; - scaledBounds[1] = h; - M_inv.mapPoints(scaledBounds); - } - - // real pixel coordinates - public void moveTo(float x, float y) { - point.x = x; - point.y = y; - mapPointF(M_inv, point); - repositionArms(); - } - - public boolean hitTest(float x, float y) { - ptmp[0] = x; - ptmp[1] = y; - M_inv.mapPoints(ptmp); - return Math.hypot(ptmp[0] - point.x, ptmp[1] - point.y) < BASE_SCALE/2; - } - - private void lockArms(boolean l) { - for (Arm arm : mArms) { - arm.setLocked(l); - } - } - private void repositionArms() { - for (int i=0; i<mArms.length; i++) { - final float bias = (float)i/(mArms.length-1) - 0.5f; - mArms[i].setAnchor( - point.x+bias*30f,point.y+26f); - } - invalidateSelf(); - } - - private void drawPupil(Canvas canvas, float x, float y, float size, boolean open, - Paint pt) { - final float r = open ? size*.33f : size * .1f; - canvas.drawRoundRect(x - size, y - r, x + size, y + r, r, r, pt); - } - - @Override - public void draw(@NonNull Canvas canvas) { - canvas.save(); - { - canvas.concat(M); - - // arms behind - mPaint.setColor(ARM_COLOR_BACK); - for (int i : BACK_ARMS) { - mArms[i].draw(canvas, mPaint); - } - - // head/body/thing - mPaint.setColor(EYE_COLOR); - canvas.drawCircle(point.x, point.y, 36f, mPaint); - mPaint.setColor(BODY_COLOR); - canvas.save(); - { - canvas.clipOutRect(point.x - 61f, point.y + 8f, - point.x + 61f, point.y + 12f); - canvas.drawOval(point.x-40f,point.y-60f,point.x+40f,point.y+40f, mPaint); - } - canvas.restore(); - - // eyes - mPaint.setColor(EYE_COLOR); - if (mBlinking) { - drawPupil(canvas, point.x - 16f, point.y - 12f, 6f, false, mPaint); - drawPupil(canvas, point.x + 16f, point.y - 12f, 6f, false, mPaint); - } else { - canvas.drawCircle(point.x - 16f, point.y - 12f, 6f, mPaint); - canvas.drawCircle(point.x + 16f, point.y - 12f, 6f, mPaint); - } - - // too much? - if (false) { - mPaint.setColor(0xFF000000); - drawPupil(canvas, point.x - 16f, point.y - 12f, 5f, true, mPaint); - drawPupil(canvas, point.x + 16f, point.y - 12f, 5f, true, mPaint); - } - - // arms in front - mPaint.setColor(ARM_COLOR); - for (int i : FRONT_ARMS) { - mArms[i].draw(canvas, mPaint); - } - - if (PATH_DEBUG) for (Arm arm : mArms) { - arm.drawDebug(canvas); - } - } - canvas.restore(); - } - - public void setBlinking(boolean b) { - mBlinking = b; - invalidateSelf(); - } - - @Override - public void setAlpha(int i) { - } - - @Override - public void setColorFilter(@Nullable ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - static Path pathMoveTo(Path p, PointF pt) { - p.moveTo(pt.x, pt.y); - return p; - } - static Path pathQuadTo(Path p, PointF p1, PointF p2) { - p.quadTo(p1.x, p1.y, p2.x, p2.y); - return p; - } - - static void mapPointF(Matrix m, PointF point) { - float[] p = new float[2]; - p[0] = point.x; - p[1] = point.y; - m.mapPoints(p); - point.x = p[0]; - point.y = p[1]; - } - - private class Link // he come to town - implements DynamicAnimation.OnAnimationUpdateListener { - final FloatValueHolder[] coords = new FloatValueHolder[2]; - final SpringAnimation[] anims = new SpringAnimation[coords.length]; - private float dx, dy; - private boolean locked = false; - Link next; - - Link(int index, float x1, float y1, float dx, float dy) { - coords[0] = new FloatValueHolder(x1); - coords[1] = new FloatValueHolder(y1); - this.dx = dx; - this.dy = dy; - for (int i=0; i<coords.length; i++) { - anims[i] = new SpringAnimation(coords[i]); - anims[i].setSpring(new SpringForce() - .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) - .setStiffness( - index == 0 ? SpringForce.STIFFNESS_LOW - : index == 1 ? SpringForce.STIFFNESS_VERY_LOW - : SpringForce.STIFFNESS_VERY_LOW/2) - .setFinalPosition(0f)); - anims[i].addUpdateListener(this); - } - } - public void setLocked(boolean locked) { - this.locked = locked; - } - public PointF start() { - return new PointF(coords[0].getValue(), coords[1].getValue()); - } - public PointF end() { - return new PointF(coords[0].getValue()+dx,coords[1].getValue()+dy); - } - public PointF mid() { - return new PointF( - 0.5f*dx+(coords[0].getValue()), - 0.5f*dy+(coords[1].getValue())); - } - public void animateTo(PointF target) { - if (locked) { - setStart(target.x, target.y); - } else { - anims[0].animateToFinalPosition(target.x); - anims[1].animateToFinalPosition(target.y); - } - } - @Override - public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) { - if (next != null) { - next.animateTo(end()); - } - OctopusDrawable.this.invalidateSelf(); - } - - public void setStart(float x, float y) { - coords[0].setValue(x); - coords[1].setValue(y); - onAnimationUpdate(null, 0, 0); - } - } - - private class Arm { - final Link link1, link2, link3; - float max, min; - - public Arm(float x, float y, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3, - float max, float min) { - link1 = new Link(0, x, y, dx1, dy1); - link2 = new Link(1, x+dx1, y+dy1, dx2, dy2); - link3 = new Link(2, x+dx1+dx2, y+dy1+dy2, dx3, dy3); - link1.next = link2; - link2.next = link3; - - link1.setLocked(true); - link2.setLocked(false); - link3.setLocked(false); - - this.max = max; - this.min = min; - } - - // when the arm is locked, it moves rigidly, without physics - public void setLocked(boolean locked) { - link2.setLocked(locked); - link3.setLocked(locked); - } - - private void setAnchor(float x, float y) { - link1.setStart(x,y); - } - - public Path getPath() { - Path p = new Path(); - pathMoveTo(p, link1.start()); - pathQuadTo(p, link2.start(), link2.mid()); - pathQuadTo(p, link2.end(), link3.end()); - return p; - } - - public void draw(@NonNull Canvas canvas, Paint pt) { - final Path p = getPath(); - TaperedPathStroke.drawPath(canvas, p, max, min, pt); - } - - private final Paint dpt = new Paint(); - public void drawDebug(Canvas canvas) { - dpt.setStyle(Paint.Style.STROKE); - dpt.setStrokeWidth(0.75f); - dpt.setStrokeCap(Paint.Cap.ROUND); - - dpt.setAntiAlias(true); - dpt.setColor(0xFF336699); - - final Path path = getPath(); - canvas.drawPath(path, dpt); - - dpt.setColor(0xFFFFFF00); - - dpt.setPathEffect(new DashPathEffect(new float[] {2f, 2f}, 0f)); - - canvas.drawLines(new float[] { - link1.end().x, link1.end().y, - link2.start().x, link2.start().y, - - link2.end().x, link2.end().y, - link3.start().x, link3.start().y, - }, dpt); - dpt.setPathEffect(null); - - dpt.setColor(0xFF00CCFF); - - canvas.drawLines(new float[] { - link1.start().x, link1.start().y, - link1.end().x, link1.end().y, - - link2.start().x, link2.start().y, - link2.end().x, link2.end().y, - - link3.start().x, link3.start().y, - link3.end().x, link3.end().y, - }, dpt); - - dpt.setColor(0xFFCCEEFF); - canvas.drawCircle(link2.start().x, link2.start().y, 2f, dpt); - canvas.drawCircle(link3.start().x, link3.start().y, 2f, dpt); - - dpt.setStyle(Paint.Style.FILL_AND_STROKE); - canvas.drawCircle(link1.start().x, link1.start().y, 2f, dpt); - canvas.drawCircle(link2.mid().x, link2.mid().y, 2f, dpt); - canvas.drawCircle(link3.end().x, link3.end().y, 2f, dpt); - } - - } -} diff --git a/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java b/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java deleted file mode 100644 index e014fbc2559e..000000000000 --- a/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2017 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.egg.octo; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PathMeasure; -import android.os.Debug; - -import java.util.Arrays; - -public class TaperedPathStroke { - static float sMinStepPx = 4f; - static PathMeasure pm = new PathMeasure(); - static float[] pos = {0,0}; - static float[] tan = {0,0}; - static float lerp(float t, float a, float b) { - return a + t*(b-a); - } - public static void setMinStep(float px) { - sMinStepPx = px; - } - - // it's the variable-width brush algorithm from the Markers app, basically - public static void drawPath(Canvas c, Path p, float r1, float r2, Paint pt) { - pm.setPath(p,false); - final float len = pm.getLength(); - float t=0; - boolean last=false; - while (true) { - if (t>=len) { - t=len; - last=true; - } - pm.getPosTan(t, pos, tan); - float r = len > 0 ? lerp(t/len, r1, r2) : r1; - c.drawCircle(pos[0], pos[1], r, pt); - t += Math.max(r*0.25f, sMinStepPx); // walk forward 1/4 radius, not too small though - if (last) break; - } - } -} diff --git a/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt new file mode 100644 index 000000000000..4a02ee688cf4 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt @@ -0,0 +1,93 @@ +/* + * 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.egg.paint + +import android.content.Context +import android.graphics.* +import android.graphics.PixelFormat.TRANSLUCENT +import android.graphics.drawable.Drawable +import android.util.DisplayMetrics + +class BrushPropertyDrawable : Drawable { + val framePaint = Paint(Paint.ANTI_ALIAS_FLAG).also { + it.color = Color.BLACK + it.style = Paint.Style.FILL + } + val wellPaint = Paint(Paint.ANTI_ALIAS_FLAG).also { + it.color = Color.RED + it.style = Paint.Style.FILL + } + + constructor(context: Context) { + _size = (24 * context.resources.displayMetrics.density).toInt() + } + + private var _size = 24 + private var _scale = 1f + + fun setFrameColor(color: Int) { + framePaint.color = color + invalidateSelf() + } + + fun setWellColor(color: Int) { + wellPaint.color = color + invalidateSelf() + } + + fun setWellScale(scale: Float) { + _scale = scale + invalidateSelf() + } + + override fun getIntrinsicWidth(): Int { + return _size + } + + override fun getIntrinsicHeight(): Int { + return _size + } + + override fun draw(c: Canvas?) { + c?.let { + val w = bounds.width().toFloat() + val h = bounds.height().toFloat() + val inset = _size / 12 // 2dp in a 24x24 icon + val r = Math.min(w, h) / 2 + + c.drawCircle(w/2, h/2, (r - inset) * _scale + 1 , wellPaint) + + val p = Path() + p.addCircle(w/2, h/2, r, Path.Direction.CCW) + p.addCircle(w/2, h/2, r - inset, Path.Direction.CW) + c.drawPath(p, framePaint) + } + } + + override fun setAlpha(p0: Int) { + // + } + + override fun getOpacity(): Int { + return TRANSLUCENT + } + + override fun setColorFilter(p0: ColorFilter?) { + // + } + +}
\ No newline at end of file diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt new file mode 100644 index 000000000000..164fc5a5af3d --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt @@ -0,0 +1,88 @@ +/* + * 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.egg.paint + +import android.content.Context +import android.util.AttributeSet +import android.view.* +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.widget.LinearLayout + +class CutoutAvoidingToolbar : LinearLayout { + private var _insets: WindowInsets? = null + + constructor(context: Context) : super(context) { + init(null, 0) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(attrs, 0) + } + + constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { + init(attrs, defStyle) + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + adjustLayout() + } + + override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets { + _insets = insets + adjustLayout() + return super.onApplyWindowInsets(insets) + } + + fun adjustLayout() { + _insets?.displayCutout?.boundingRects?.let { + var cutoutCenter = 0 + var cutoutLeft = 0 + var cutoutRight = 0 + + // collect at most three cutouts + for (r in it) { + if (r.top > 0) continue + + if (r.left == left) { + cutoutLeft = r.width() + } else if (r.right == right) { + cutoutRight = r.width() + } else { + cutoutCenter = r.width() + } + } + + // apply to layout + (findViewWithTag("cutoutLeft") as View?)?.let { + it.layoutParams = LayoutParams(cutoutLeft, MATCH_PARENT) + } + (findViewWithTag("cutoutCenter") as View?)?.let { + it.layoutParams = LayoutParams(cutoutCenter, MATCH_PARENT) + } + (findViewWithTag("cutoutRight") as View?)?.let { + it.layoutParams = LayoutParams(cutoutRight, MATCH_PARENT) + } + + requestLayout() + } + } + + private fun init(attrs: AttributeSet?, defStyle: Int) { + } + +} diff --git a/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java b/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java new file mode 100644 index 000000000000..ac47fbda09c6 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java @@ -0,0 +1,351 @@ +/* + * 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.egg.paint; + +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_UP; + +import android.app.Activity; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.Magnifier; + +import com.android.egg.R; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.IntStream; + +public class PaintActivity extends Activity { + private static final float MAX_BRUSH_WIDTH_DP = 100f; + private static final float MIN_BRUSH_WIDTH_DP = 1f; + + private static final int NUM_BRUSHES = 6; + private static final int NUM_COLORS = 6; + + private Painting painting = null; + private CutoutAvoidingToolbar toolbar = null; + private LinearLayout brushes = null; + private LinearLayout colors = null; + private Magnifier magnifier = null; + private boolean sampling = false; + + private View.OnClickListener buttonHandler = new View.OnClickListener() { + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btnBrush: + view.setSelected(true); + hideToolbar(colors); + toggleToolbar(brushes); + break; + case R.id.btnColor: + view.setSelected(true); + hideToolbar(brushes); + toggleToolbar(colors); + break; + case R.id.btnClear: + painting.clear(); + break; + case R.id.btnSample: + sampling = true; + view.setSelected(true); + break; + case R.id.btnZen: + painting.setZenMode(!painting.getZenMode()); + view.animate() + .setStartDelay(200) + .setInterpolator(new OvershootInterpolator()) + .rotation(painting.getZenMode() ? 0f : 90f); + break; + } + } + }; + + private void showToolbar(View bar) { + if (bar.getVisibility() != View.GONE) return; + bar.setVisibility(View.VISIBLE); + bar.setTranslationY(toolbar.getHeight()/2); + bar.animate() + .translationY(toolbar.getHeight()) + .alpha(1f) + .setDuration(220) + .start(); + } + + private void hideToolbar(View bar) { + if (bar.getVisibility() != View.VISIBLE) return; + bar.animate() + .translationY(toolbar.getHeight()/2) + .alpha(0f) + .setDuration(150) + .withEndAction(new Runnable() { + @Override + public void run() { + bar.setVisibility(View.GONE); + } + }) + .start(); + } + + private void toggleToolbar(View bar) { + if (bar.getVisibility() == View.VISIBLE) { + hideToolbar(bar); + } else { + showToolbar(bar); + } + } + + private BrushPropertyDrawable widthButtonDrawable; + private BrushPropertyDrawable colorButtonDrawable; + private float maxBrushWidth, minBrushWidth; + private int nightMode = Configuration.UI_MODE_NIGHT_UNDEFINED; + + static final float lerp(float f, float a, float b) { + return a + (b-a) * f; + } + + void setupViews(Painting oldPainting) { + setContentView(R.layout.activity_paint); + + painting = oldPainting != null ? oldPainting : new Painting(this); + ((FrameLayout) findViewById(R.id.contentView)).addView(painting, + new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + + painting.setPaperColor(getColor(R.color.paper_color)); + painting.setPaintColor(getColor(R.color.paint_color)); + + toolbar = findViewById(R.id.toolbar); + brushes = findViewById(R.id.brushes); + colors = findViewById(R.id.colors); + + magnifier = new Magnifier(painting); + + painting.setOnTouchListener( + new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent event) { + switch (event.getActionMasked()) { + case ACTION_DOWN: + case ACTION_MOVE: + if (sampling) { + magnifier.show(event.getX(), event.getY()); + colorButtonDrawable.setWellColor( + painting.sampleAt(event.getX(), event.getY())); + return true; + } + break; + case ACTION_CANCEL: + if (sampling) { + findViewById(R.id.btnSample).setSelected(false); + sampling = false; + magnifier.dismiss(); + } + break; + case ACTION_UP: + if (sampling) { + findViewById(R.id.btnSample).setSelected(false); + sampling = false; + magnifier.dismiss(); + painting.setPaintColor( + painting.sampleAt(event.getX(), event.getY())); + refreshBrushAndColor(); + } + break; + } + return false; // allow view to continue handling + } + }); + + findViewById(R.id.btnBrush).setOnClickListener(buttonHandler); + findViewById(R.id.btnColor).setOnClickListener(buttonHandler); + findViewById(R.id.btnClear).setOnClickListener(buttonHandler); + findViewById(R.id.btnSample).setOnClickListener(buttonHandler); + findViewById(R.id.btnZen).setOnClickListener(buttonHandler); + + findViewById(R.id.btnColor).setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + colors.removeAllViews(); + showToolbar(colors); + refreshBrushAndColor(); + return true; + } + }); + + findViewById(R.id.btnClear).setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + painting.invertContents(); + return true; + } + }); + + widthButtonDrawable = new BrushPropertyDrawable(this); + widthButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color)); + colorButtonDrawable = new BrushPropertyDrawable(this); + colorButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color)); + + ((ImageButton) findViewById(R.id.btnBrush)).setImageDrawable(widthButtonDrawable); + ((ImageButton) findViewById(R.id.btnColor)).setImageDrawable(colorButtonDrawable); + + refreshBrushAndColor(); + } + + private void refreshBrushAndColor() { + final LinearLayout.LayoutParams button_lp = new LinearLayout.LayoutParams( + 0, ViewGroup.LayoutParams.WRAP_CONTENT); + button_lp.weight = 1f; + if (brushes.getChildCount() == 0) { + for (int i = 0; i < NUM_BRUSHES; i++) { + final BrushPropertyDrawable icon = new BrushPropertyDrawable(this); + icon.setFrameColor(getColor(R.color.toolbar_icon_color)); + // exponentially increasing brush size + final float width = lerp( + (float) Math.pow((float) i / NUM_BRUSHES, 2f), minBrushWidth, + maxBrushWidth); + icon.setWellScale(width / maxBrushWidth); + icon.setWellColor(getColor(R.color.toolbar_icon_color)); + final ImageButton button = new ImageButton(this); + button.setImageDrawable(icon); + button.setBackground(getDrawable(R.drawable.toolbar_button_bg)); + button.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + brushes.setSelected(false); + hideToolbar(brushes); + painting.setBrushWidth(width); + refreshBrushAndColor(); + } + }); + brushes.addView(button, button_lp); + } + } + + if (colors.getChildCount() == 0) { + final Palette pal = new Palette(NUM_COLORS); + for (final int c : IntStream.concat( + IntStream.of(Color.BLACK, Color.WHITE), + Arrays.stream(pal.getColors()) + ).toArray()) { + final BrushPropertyDrawable icon = new BrushPropertyDrawable(this); + icon.setFrameColor(getColor(R.color.toolbar_icon_color)); + icon.setWellColor(c); + final ImageButton button = new ImageButton(this); + button.setImageDrawable(icon); + button.setBackground(getDrawable(R.drawable.toolbar_button_bg)); + button.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + colors.setSelected(false); + hideToolbar(colors); + painting.setPaintColor(c); + refreshBrushAndColor(); + } + }); + colors.addView(button, button_lp); + } + } + + widthButtonDrawable.setWellScale(painting.getBrushWidth() / maxBrushWidth); + widthButtonDrawable.setWellColor(painting.getPaintColor()); + colorButtonDrawable.setWellColor(painting.getPaintColor()); + } + + private void refreshNightMode(Configuration config) { + int newNightMode = + (config.uiMode & Configuration.UI_MODE_NIGHT_MASK); + if (nightMode != newNightMode) { + if (nightMode != Configuration.UI_MODE_NIGHT_UNDEFINED) { + painting.invertContents(); + + ((ViewGroup) painting.getParent()).removeView(painting); + setupViews(painting); + + final View decorView = getWindow().getDecorView(); + int decorSUIV = decorView.getSystemUiVisibility(); + + if (newNightMode == Configuration.UI_MODE_NIGHT_YES) { + decorView.setSystemUiVisibility( + decorSUIV & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); + } else { + decorView.setSystemUiVisibility( + decorSUIV | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); + } + } + nightMode = newNightMode; + } + } + + public PaintActivity() { + + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + + painting.onTrimMemory(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + refreshNightMode(newConfig); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WindowManager.LayoutParams lp = getWindow().getAttributes(); + lp.flags = lp.flags + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + getWindow().setAttributes(lp); + + maxBrushWidth = MAX_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density; + minBrushWidth = MIN_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density; + + setupViews(null); + refreshNightMode(getResources().getConfiguration()); + } + + @Override + public void onPostResume() { + super.onPostResume(); + } + +} diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt new file mode 100644 index 000000000000..a4a3d3d835e0 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt @@ -0,0 +1,358 @@ +/* + * 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.egg.paint + +import android.content.Context +import android.content.res.Resources +import android.graphics.* +import android.provider.Settings +import android.util.AttributeSet +import android.util.DisplayMetrics +import android.view.MotionEvent +import android.view.View +import android.view.WindowInsets +import java.util.concurrent.TimeUnit +import android.util.Log +import android.provider.Settings.System + +import org.json.JSONObject + +fun hypot(x: Float, y: Float): Float { + return Math.hypot(x.toDouble(), y.toDouble()).toFloat() +} + +fun invlerp(x: Float, a: Float, b: Float): Float { + return if (b > a) { + (x - a) / (b - a) + } else 1.0f +} + +public class Painting : View, SpotFilter.Plotter { + companion object { + val FADE_MINS = TimeUnit.MINUTES.toMillis(3) // about how long a drawing should last + val ZEN_RATE = TimeUnit.SECONDS.toMillis(2) // how often to apply the fade + val ZEN_FADE = Math.max(1f, ZEN_RATE / FADE_MINS * 255f) + + val FADE_TO_WHITE_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf( + 1f, 0f, 0f, 0f, ZEN_FADE, + 0f, 1f, 0f, 0f, ZEN_FADE, + 0f, 0f, 1f, 0f, ZEN_FADE, + 0f, 0f, 0f, 1f, 0f + ))) + + val FADE_TO_BLACK_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf( + 1f, 0f, 0f, 0f, -ZEN_FADE, + 0f, 1f, 0f, 0f, -ZEN_FADE, + 0f, 0f, 1f, 0f, -ZEN_FADE, + 0f, 0f, 0f, 1f, 0f + ))) + + val INVERT_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf( + -1f, 0f, 0f, 0f, 255f, + 0f, -1f, 0f, 0f, 255f, + 0f, 0f, -1f, 0f, 255f, + 0f, 0f, 0f, 1f, 0f + ))) + + val TOUCH_STATS = "touch.stats" // Settings.System key + } + + var devicePressureMin = 0f; // ideal value + var devicePressureMax = 1f; // ideal value + + var zenMode = true + set(value) { + if (field != value) { + field = value + removeCallbacks(fadeRunnable) + if (value && isAttachedToWindow) { + handler.postDelayed(fadeRunnable, ZEN_RATE) + } + } + } + + var bitmap: Bitmap? = null + var paperColor : Int = 0xFFFFFFFF.toInt() + + private var _paintCanvas: Canvas? = null + private val _bitmapLock = Object() + + private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG) + private var _lastX = 0f + private var _lastY = 0f + private var _lastR = 0f + private var _insets: WindowInsets? = null + + private var _brushWidth = 100f + + private var _filter = SpotFilter(10, 0.5f, 0.9f, this) + + private val fadeRunnable = object : Runnable { + private val pt = Paint() + override fun run() { + val c = _paintCanvas + if (c != null) { + pt.colorFilter = + if (paperColor.and(0xFF) > 0x80) + FADE_TO_WHITE_CF + else + FADE_TO_BLACK_CF + + synchronized(_bitmapLock) { + c.drawBitmap(bitmap, 0f, 0f, pt) + } + invalidate() + } + postDelayed(this, ZEN_RATE) + } + } + + constructor(context: Context) : super(context) { + init(null, 0) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(attrs, 0) + } + + constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { + init(attrs, defStyle) + } + + private fun init(attrs: AttributeSet?, defStyle: Int) { + loadDevicePressureData() + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + setupBitmaps() + + if (zenMode) { + handler.postDelayed(fadeRunnable, ZEN_RATE) + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + setupBitmaps() + } + + override fun onDetachedFromWindow() { + if (zenMode) { + removeCallbacks(fadeRunnable) + } + super.onDetachedFromWindow() + } + + fun onTrimMemory() { + } + + override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets { + _insets = insets + if (insets != null && _paintCanvas == null) { + setupBitmaps() + } + return super.onApplyWindowInsets(insets) + } + + private fun powf(a: Float, b: Float): Float { + return Math.pow(a.toDouble(), b.toDouble()).toFloat() + } + + override fun plot(s: MotionEvent.PointerCoords) { + val c = _paintCanvas + if (c == null) return + synchronized(_bitmapLock) { + var x = _lastX + var y = _lastY + var r = _lastR + val newR = Math.max(1f, powf(adjustPressure(s.pressure), 2f).toFloat() * _brushWidth) + + if (r >= 0) { + val d = hypot(s.x - x, s.y - y) + if (d > 1f && (r + newR) > 1f) { + val N = (2 * d / Math.min(4f, r + newR)).toInt() + + val stepX = (s.x - x) / N + val stepY = (s.y - y) / N + val stepR = (newR - r) / N + for (i in 0 until N - 1) { // we will draw the last circle below + x += stepX + y += stepY + r += stepR + c.drawCircle(x, y, r, _drawPaint) + } + } + } + + c.drawCircle(s.x, s.y, newR, _drawPaint) + _lastX = s.x + _lastY = s.y + _lastR = newR + } + } + + private fun loadDevicePressureData() { + try { + val touchDataJson = Settings.System.getString(context.contentResolver, TOUCH_STATS) + val touchData = JSONObject( + if (touchDataJson != null) touchDataJson else "{}") + if (touchData.has("min")) devicePressureMin = touchData.getDouble("min").toFloat() + if (touchData.has("max")) devicePressureMax = touchData.getDouble("max").toFloat() + if (devicePressureMin < 0) devicePressureMin = 0f + if (devicePressureMax < devicePressureMin) devicePressureMax = devicePressureMin + 1f + } catch (e: Exception) { + } + } + + private fun adjustPressure(pressure: Float): Float { + if (pressure > devicePressureMax) devicePressureMax = pressure + if (pressure < devicePressureMin) devicePressureMin = pressure + return invlerp(pressure, devicePressureMin, devicePressureMax) + } + + override fun onTouchEvent(event: MotionEvent?): Boolean { + val c = _paintCanvas + if (event == null || c == null) return super.onTouchEvent(event) + + /* + val pt = Paint(Paint.ANTI_ALIAS_FLAG) + pt.style = Paint.Style.STROKE + pt.color = 0x800000FF.toInt() + _paintCanvas?.drawCircle(event.x, event.y, 20f, pt) + */ + + when (event.actionMasked) { + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + _filter.add(event) + _filter.finish() + invalidate() + } + + MotionEvent.ACTION_DOWN -> { + _lastR = -1f + _filter.add(event) + invalidate() + } + + MotionEvent.ACTION_MOVE -> { + _filter.add(event) + + invalidate() + } + } + + return true + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + bitmap?.let { + canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint); + } + } + + // public api + fun clear() { + bitmap = null + setupBitmaps() + invalidate() + } + + fun sampleAt(x: Float, y: Float): Int { + val localX = (x - left).toInt() + val localY = (y - top).toInt() + return bitmap?.getPixel(localX, localY) ?: Color.BLACK + } + + fun setPaintColor(color: Int) { + _drawPaint.color = color + } + + fun getPaintColor(): Int { + return _drawPaint.color + } + + fun setBrushWidth(w: Float) { + _brushWidth = w + } + + fun getBrushWidth(): Float { + return _brushWidth + } + + private fun setupBitmaps() { + val dm = DisplayMetrics() + display.getRealMetrics(dm) + val w = dm.widthPixels + val h = dm.heightPixels + val oldBits = bitmap + var bits = oldBits + if (bits == null || bits.width != w || bits.height != h) { + bits = Bitmap.createBitmap( + w, + h, + Bitmap.Config.ARGB_8888 + ) + } + if (bits == null) return + + val c = Canvas(bits) + + if (oldBits != null) { + if (oldBits.width < oldBits.height != bits.width < bits.height) { + // orientation change. let's rotate things so they fit better + val matrix = Matrix() + if (bits.width > bits.height) { + // now landscape + matrix.postRotate(-90f) + matrix.postTranslate(0f, bits.height.toFloat()) + } else { + // now portrait + matrix.postRotate(90f) + matrix.postTranslate(bits.width.toFloat(), 0f) + } + if (bits.width != oldBits.height || bits.height != oldBits.width) { + matrix.postScale( + bits.width.toFloat()/oldBits.height, + bits.height.toFloat()/oldBits.width) + } + c.matrix = matrix + } + // paint the old artwork atop the new + c.drawBitmap(oldBits, 0f, 0f, _drawPaint) + c.matrix = Matrix() + } else { + c.drawColor(paperColor) + } + + bitmap = bits + _paintCanvas = c + } + + fun invertContents() { + val invertPaint = Paint() + invertPaint.colorFilter = INVERT_CF + synchronized(_bitmapLock) { + _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint) + } + invalidate() + } +} + diff --git a/packages/EasterEgg/src/com/android/egg/paint/Palette.kt b/packages/EasterEgg/src/com/android/egg/paint/Palette.kt new file mode 100644 index 000000000000..7043efe1f4f5 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/Palette.kt @@ -0,0 +1,83 @@ +/* + * 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.egg.paint + +import android.graphics.Color + +class Palette { + var colors : IntArray + var lightest = 0 + var darkest = 0 + + /** + * rough luminance calculation + * https://www.w3.org/TR/AERT/#color-contrast + */ + private fun lum(rgb: Int): Float { + return (Color.red(rgb) * 299f + Color.green(rgb) * 587f + Color.blue(rgb) * 114f) / 1000f + } + + /** + * create a random evenly-spaced color palette + * guaranteed to contrast! + */ + fun randomize(S: Float, V: Float) { + val hsv = floatArrayOf((Math.random() * 360f).toFloat(), S, V) + val count = colors.size + colors[0] = Color.HSVToColor(hsv) + lightest = 0 + darkest = 0 + + for (i in 0 until count) { + hsv[0] = (hsv[0] + 360f / count).rem(360f) + val color = Color.HSVToColor(hsv) + colors[i] = color + + val lum = lum(colors[i]) + if (lum < lum(colors[darkest])) darkest = i + if (lum > lum(colors[lightest])) lightest = i + } + } + + override fun toString() : String { + val str = StringBuilder("Palette{ ") + for (c in colors) { + str.append(String.format("#%08x ", c)) + } + str.append("}") + return str.toString() + } + + constructor(count: Int) { + colors = IntArray(count) + randomize(1f, 1f) + } + + constructor(count: Int, S: Float, V: Float) { + colors = IntArray(count) + randomize(S, V) + } + + constructor(_colors: IntArray) { + colors = _colors + for (i in 0 until colors.size) { + val lum = lum(colors[i]) + if (lum < lum(colors[darkest])) darkest = i + if (lum > lum(colors[lightest])) lightest = i + } + } +}
\ No newline at end of file diff --git a/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt b/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt new file mode 100644 index 000000000000..2c15c0dc4861 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt @@ -0,0 +1,124 @@ +/* + * 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.egg.paint + +import java.util.LinkedList + +import android.view.MotionEvent + +class SpotFilter(internal var mBufSize: Int, posDecay: Float, pressureDecay: Float, internal var mPlotter: Plotter) { + val spots = LinkedList<MotionEvent.PointerCoords>() // newest at front + val tmpSpot = MotionEvent.PointerCoords() + var lastTool = MotionEvent.TOOL_TYPE_UNKNOWN + + val posDecay: Float + val pressureDecay: Float + + interface Plotter { + fun plot(s: MotionEvent.PointerCoords) + } + + init { + this.posDecay = if (posDecay in 0f..1f) posDecay else 1f + this.pressureDecay = if (pressureDecay in 0f..1f) pressureDecay else 1f + } + + fun filterInto(out: MotionEvent.PointerCoords, tool: Int): MotionEvent.PointerCoords { + lastTool = tool + + var wi = 1f // weight for ith component (position) + var w = 0f // total weight + var wi_press = 1f // weight for ith component (pressure) + var w_press = 0f // total weight (pressure) + + var x = 0f + var y = 0f + var pressure = 0f + var size = 0f + for (pi in spots) { + x += pi.x * wi + y += pi.y * wi + + pressure += pi.pressure * wi_press + size += pi.size * wi_press + + w += wi + wi *= posDecay // exponential backoff + + w_press += wi_press + wi_press *= pressureDecay + + if (PRECISE_STYLUS_INPUT && tool == MotionEvent.TOOL_TYPE_STYLUS) { + // just take the newest one, no need to average + break + } + } + + out.x = x / w + out.y = y / w + out.pressure = pressure / w_press + out.size = size / w_press + return out + } + + protected fun addInternal(c: MotionEvent.PointerCoords, tool: Int) { + val coord = + if (spots.size == mBufSize) { + spots.removeLast() + } else { + MotionEvent.PointerCoords() + } + coord.copyFrom(c) + + spots.add(0, coord) + + filterInto(tmpSpot, tool) + mPlotter.plot(tmpSpot) + } + + fun add(cv: List<MotionEvent.PointerCoords>, tool: Int) { + for (c in cv) { + addInternal(c, tool) + } + } + + fun add(evt: MotionEvent) { + val tool = evt.getToolType(0) + for (i in 0 until evt.historySize) { + evt.getHistoricalPointerCoords(0, i, tmpSpot) + addInternal(tmpSpot, tool) + } + evt.getPointerCoords(0, tmpSpot) + addInternal(tmpSpot, tool) + } + + fun finish() { + while (spots.size > 0) { + filterInto(tmpSpot, lastTool) + spots.removeLast() + mPlotter.plot(tmpSpot) + } + + spots.clear() + } + + companion object { + var PRECISE_STYLUS_INPUT = true + } +} + + diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt new file mode 100644 index 000000000000..86b11e7be81e --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt @@ -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.egg.paint + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.text.TextPaint +import android.transition.ChangeBounds +import android.transition.Transition +import android.transition.TransitionListenerAdapter +import android.transition.TransitionManager +import android.util.AttributeSet +import android.view.* +import android.view.animation.OvershootInterpolator +import android.widget.FrameLayout + +class ToolbarView : FrameLayout { + var inTransition = false + var transitionListener: Transition.TransitionListener = object : TransitionListenerAdapter() { + override fun onTransitionStart(transition: Transition?) { + inTransition = true + } + override fun onTransitionEnd(transition: Transition?) { + inTransition = false + } + } + + constructor(context: Context) : super(context) { + init(null, 0) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(attrs, 0) + } + + constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { + init(attrs, defStyle) + } + + override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets { + var lp = layoutParams as FrameLayout.LayoutParams? + if (lp != null && insets != null) { + if (insets.hasStableInsets()) { + lp.topMargin = insets.stableInsetTop + lp.bottomMargin = insets.stableInsetBottom + } else { + lp.topMargin = insets.systemWindowInsetTop + lp.bottomMargin = insets.systemWindowInsetBottom + } + layoutParams = lp + } + + return super.onApplyWindowInsets(insets) + } + + private fun init(attrs: AttributeSet?, defStyle: Int) { + } + +} diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java index 7234788b2e04..c9990e574eed 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java @@ -16,6 +16,7 @@ package com.android.settingslib.fuelgauge; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -89,6 +90,13 @@ public class PowerWhitelistBackend { if (TextUtils.equals(pkg, defaultDialer)) { return true; } + + final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService( + DevicePolicyManager.class); + if (devicePolicyManager.packageHasActiveAdmins(pkg)) { + return true; + } + return false; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java index a23eebcce797..5c932586dd28 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java @@ -21,8 +21,10 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -51,7 +53,8 @@ public class PowerWhitelistBackendTest { @Mock private IDeviceIdleController mDeviceIdleService; - + @Mock + private DevicePolicyManager mDevicePolicyManager; private PowerWhitelistBackend mPowerWhitelistBackend; private ShadowPackageManager mPackageManager; private Context mContext; @@ -59,7 +62,9 @@ public class PowerWhitelistBackendTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); + doReturn(mContext).when(mContext).getApplicationContext(); + doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class); doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); @@ -68,6 +73,7 @@ public class PowerWhitelistBackendTest { mPackageManager = Shadow.extract(mContext.getPackageManager()); mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true); + mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService); } @@ -123,6 +129,13 @@ public class PowerWhitelistBackendTest { } @Test + public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() { + doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE); + + assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); + } + + @Test public void testIsSystemWhitelisted() throws Exception { doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist(); mPowerWhitelistBackend.refreshList(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index f72868431d43..9d398b5b69a1 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -841,7 +841,19 @@ public class SettingsBackupAgent extends BackupAgentHelper { WifiConfiguration config = WifiConfiguration .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data))); if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration "); + int originalApBand = config.apBand; mWifiManager.setWifiApConfiguration(config); + + // Depending on device hardware, we may need to notify the user of a setting change for + // the apBand preference + boolean dualMode = mWifiManager.isDualModeSupported(); + int storedApBand = mWifiManager.getWifiApConfiguration().apBand; + if (dualMode) { + if (storedApBand != originalApBand) { + Log.d(TAG, "restored ap configuration requires a conversion, notify the user"); + mWifiManager.notifyUserOfApBandConversion(); + } + } } catch (IOException | BackupUtils.BadVersionException e) { Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage()); } diff --git a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png Binary files differdeleted file mode 100644 index 0899d3515f1b..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png Binary files differdeleted file mode 100644 index 22664496db76..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png Binary files differdeleted file mode 100644 index 3328add435fb..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png Binary files differdeleted file mode 100644 index ed651da88800..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png Binary files differdeleted file mode 100644 index 06e120239eb2..000000000000 --- a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png +++ /dev/null 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/colors.xml b/packages/SystemUI/res/values/colors.xml index 975055ce72e6..07f1ee084183 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -137,8 +137,10 @@ <color name="remote_input_accent">#eeeeee</color> - <color name="quick_step_track_background_dark">#61000000</color> - <color name="quick_step_track_background_light">#33FFFFFF</color> + <color name="quick_step_track_background_background_dark">#1F000000</color> + <color name="quick_step_track_background_background_light">#33FFFFFF</color> + <color name="quick_step_track_background_foreground_dark">#38000000</color> + <color name="quick_step_track_background_foreground_light">#59FFFFFF</color> <!-- Keyboard shortcuts colors --> <color name="ksh_application_group_color">#fff44336</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f00957a14e09..883ed8dd17d9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -764,9 +764,6 @@ <dimen name="volume_expander_margin_end">2dp</dimen> <dimen name="volume_expander_margin_top">6dp</dimen> - <!-- Padding between icon and text for managed profile toast --> - <dimen name="managed_profile_toast_padding">4dp</dimen> - <!-- Thickness of the assist disclosure beams --> <dimen name="assist_disclosure_thickness">2.5dp</dimen> @@ -922,14 +919,18 @@ <dimen name="global_actions_top_padding">120dp</dimen> - <!-- the maximum offset in either direction that elements are moved horizontally to prevent - burn-in on AOD --> + <!-- The maximum offset in either direction that elements are moved horizontally to prevent + burn-in on AOD. --> <dimen name="burn_in_prevention_offset_x">8dp</dimen> - <!-- the maximum offset in either direction that elements are moved vertically to prevent - burn-in on AOD --> + <!-- The maximum offset in either direction that elements are moved vertically to prevent + burn-in on AOD. --> <dimen name="burn_in_prevention_offset_y">50dp</dimen> + <!-- The maximum offset in either direction that the charging indication moves vertically + to prevent burn-in on AOD. --> + <dimen name="charging_indication_burn_in_prevention_offset_y">5dp</dimen> + <dimen name="corner_size">8dp</dimen> <dimen name="top_padding">0dp</dimen> <dimen name="bottom_padding">48dp</dimen> @@ -1012,4 +1013,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/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index edf56afad714..18f378e5919b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1326,9 +1326,6 @@ <!-- Hide quick settings tile confirmation button --> <string name="quick_settings_reset_confirmation_button">Hide</string> - <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground --> - <string name="managed_profile_foreground_toast">You\'re using your work profile</string> - <!-- volume stream names. All nouns. --> <string name="stream_voice_call">Call</string> <!-- STREAM_VOICE_CALL --> <string name="stream_system">System</string> <!-- STREAM_SYSTEM --> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java index cd831d1e31f6..d38cc0f608ce 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java @@ -54,6 +54,7 @@ public class NavigationBarCompat { public static final int HIT_TARGET_HOME = 2; public static final int HIT_TARGET_OVERVIEW = 3; public static final int HIT_TARGET_ROTATION = 4; + public static final int HIT_TARGET_DEAD_ZONE = 5; @Retention(RetentionPolicy.SOURCE) @IntDef({FLAG_DISABLE_SWIPE_UP, 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..40149464dff2 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; @@ -198,6 +199,9 @@ public class KeyguardStatusView extends GridLayout implements mClockView.setElegantTextHeight(false); } + /** + * Moves clock and separator, adjusting margins when slice content changes. + */ private void onSliceContentChanged() { boolean smallClock = mKeyguardSlice.hasHeader() || mPulsing; float clockScale = smallClock ? mSmallClockScale : 1; @@ -220,11 +224,12 @@ public class KeyguardStatusView extends GridLayout implements @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - int heightOffset = mPulsing ? 0 : getHeight() - mLastLayoutHeight; + int heightOffset = mPulsing || mWasPulsing ? 0 : getHeight() - mLastLayoutHeight; 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,7 +453,18 @@ public class KeyguardStatusView extends GridLayout implements } public void setPulsing(boolean pulsing, boolean animate) { + if (mPulsing == pulsing) { + return; + } + if (mPulsing) { + mWasPulsing = true; + } mPulsing = pulsing; + // Animation can look really weird when the slice has a header, let's hide the views + // immediately instead of fading them away. + if (mKeyguardSlice.hasHeader()) { + animate = false; + } 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/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index b8a57bfe885a..50d862dee29c 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -290,7 +290,7 @@ public class ImageWallpaper extends WallpaperService { || dh != mLastSurfaceHeight; boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation - || mSurfaceRedrawNeeded; + || mSurfaceRedrawNeeded || mNeedsDrawAfterLoadingWallpaper; if (!redrawNeeded && !mOffsetsChanged) { if (DEBUG) { Log.d(TAG, "Suppressed drawFrame since redraw is not needed " diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index aeef49689517..eb704c863ebc 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -31,6 +31,13 @@ import com.android.systemui.statusbar.stack.HeadsUpAppearInterpolator; */ public class Interpolators { public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + + /** + * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t + * goes from 1 to 0 instead of 0 to 1). + */ + public static final Interpolator FAST_OUT_SLOW_IN_REVERSE = + new PathInterpolator(0.8f, 0f, 0.6f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); @@ -51,4 +58,11 @@ public class Interpolators { */ public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f); + + /** + * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t + * goes from 1 to 0 instead of 0 to 1). + */ + public static final Interpolator TOUCH_RESPONSE_REVERSE = + new PathInterpolator(0.9f, 0f, 0.7f, 1f); } 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/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 6809e76c18e3..89688fba1cc6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -344,6 +344,11 @@ public class KeyguardViewMediator extends SystemUI { */ private WorkLockActivityController mWorkLockController; + /** + * @see #setPulsing(boolean) + */ + private boolean mPulsing; + private boolean mLockLater; private boolean mWakeAndUnlocking; @@ -1798,10 +1803,12 @@ public class KeyguardViewMediator extends SystemUI { int flags = 0; if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock() - || mWakeAndUnlocking) { - flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; + || (mWakeAndUnlocking && !mPulsing)) { + flags |= WindowManagerPolicyConstants + .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } - if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()) { + if (mStatusBarKeyguardViewManager.isGoingToNotificationShade() + || (mWakeAndUnlocking && mPulsing)) { flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; } if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) { @@ -2100,10 +2107,20 @@ public class KeyguardViewMediator extends SystemUI { pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback); } + /** + * @param aodShowing true when AOD - or ambient mode - is showing. + */ public void setAodShowing(boolean aodShowing) { setShowingLocked(mShowing, aodShowing); } + /** + * @param pulsing true when device temporarily wakes up to display an incoming notification. + */ + public void setPulsing(boolean pulsing) { + mPulsing = pulsing; + } + private static class StartKeyguardExitAnimParams { long startTime; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index cc60f8744ca7..42e5adced68d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -265,6 +265,8 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); + // Clear selected state so it is not announce by talkback. + info.setSelected(false); if (!TextUtils.isEmpty(mAccessibilityClass)) { info.setClassName(mAccessibilityClass); if (Switch.class.getName().equals(mAccessibilityClass)) { 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/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index 1287ced8594c..25684ff651fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -108,16 +108,6 @@ public class NotificationLockscreenUserManager implements Dumpable { } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { // Start the overview connection to the launcher service Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser(); - } else if (Intent.ACTION_USER_PRESENT.equals(action)) { - try { - final int lastResumedActivityUserId = - ActivityManager.getService().getLastResumedActivityUserId(); - if (mUserManager.isManagedProfile(lastResumedActivityUserId)) { - showForegroundManagedProfileActivityToast(); - } - } catch (RemoteException e) { - // Abandon hope activity manager not running. - } } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) { final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT); final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX); @@ -224,7 +214,6 @@ public class NotificationLockscreenUserManager implements Dumpable { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_ADDED); - filter.addAction(Intent.ACTION_USER_PRESENT); filter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiver(mBaseBroadcastReceiver, filter); @@ -237,19 +226,6 @@ public class NotificationLockscreenUserManager implements Dumpable { mSettingsObserver.onChange(false); // set up } - private void showForegroundManagedProfileActivityToast() { - Toast toast = Toast.makeText(mContext, - R.string.managed_profile_foreground_toast, - Toast.LENGTH_SHORT); - TextView text = toast.getView().findViewById(android.R.id.message); - text.setCompoundDrawablesRelativeWithIntrinsicBounds( - R.drawable.stat_sys_managed_profile_status, 0, 0, 0); - int paddingPx = mContext.getResources().getDimensionPixelSize( - R.dimen.managed_profile_toast_padding); - text.setCompoundDrawablePadding(paddingPx); - toast.show(); - } - public boolean shouldShowLockscreenNotifications() { return mShowLockscreenNotifications; } 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/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java index f0b1a82cfc2f..7cb6a192c64a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java @@ -210,15 +210,28 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { // until the clock and the notifications are faded out. mStatusBarWindowManager.setForceDozeBrightness(true); } - if (!wasDeviceInteractive) { - if (DEBUG_FP_WAKELOCK) { - Log.i(TAG, "fp wakelock: Authenticated, waking up..."); + // During wake and unlock, we need to draw black before waking up to avoid abrupt + // brightness changes due to display state transitions. + boolean alwaysOnEnabled = DozeParameters.getInstance(mContext).getAlwaysOn(); + boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled; + Runnable wakeUp = ()-> { + if (!wasDeviceInteractive) { + if (DEBUG_FP_WAKELOCK) { + Log.i(TAG, "fp wakelock: Authenticated, waking up..."); + } + mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT"); + } + if (delayWakeUp) { + mKeyguardViewMediator.onWakeAndUnlocking(); } - mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT"); + Trace.beginSection("release wake-and-unlock"); + releaseFingerprintWakeLock(); + Trace.endSection(); + }; + + if (!delayWakeUp) { + wakeUp.run(); } - Trace.beginSection("release wake-and-unlock"); - releaseFingerprintWakeLock(); - Trace.endSection(); switch (mMode) { case MODE_DISMISS_BOUNCER: Trace.beginSection("MODE_DISMISS"); @@ -251,7 +264,11 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { mUpdateMonitor.awakenFromDream(); } mStatusBarWindowManager.setStatusBarFocusable(false); - mKeyguardViewMediator.onWakeAndUnlocking(); + if (delayWakeUp) { + mHandler.postDelayed(wakeUp, 50); + } else { + mKeyguardViewMediator.onWakeAndUnlocking(); + } if (mStatusBar.getNavigationBarView() != null) { mStatusBar.getNavigationBarView().setWakeAndUnlocking(true); } 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/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 0716b37ff8d9..60d62d52995d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -172,6 +172,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private int mIndicationBottomMarginAmbient; private float mDarkAmount; private int mBurnInXOffset; + private int mBurnInYOffset; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -245,6 +246,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL R.dimen.keyguard_indication_margin_bottom); mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_margin_bottom_ambient); + mBurnInYOffset = getResources().getDimensionPixelSize( + R.dimen.charging_indication_burn_in_prevention_offset_y); updateCameraVisibility(); mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); mUnlockMethodCache.addListener(this); @@ -317,6 +320,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL R.dimen.keyguard_indication_margin_bottom); mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_margin_bottom_ambient); + mBurnInYOffset = getResources().getDimensionPixelSize( + R.dimen.charging_indication_burn_in_prevention_offset_y); MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams(); if (mlp.bottomMargin != mIndicationBottomMargin) { mlp.bottomMargin = mIndicationBottomMargin; @@ -560,12 +565,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return; } mDarkAmount = darkAmount; - // Let's randomize the bottom margin every time we wake up to avoid burn-in. - if (darkAmount == 0) { - mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize( - R.dimen.keyguard_indication_margin_bottom_ambient) - + (int) (Math.random() * mIndicationText.getTextSize()); - } mIndicationArea.setAlpha(MathUtils.lerp(1f, 0.7f, darkAmount)); mIndicationArea.setTranslationY(MathUtils.lerp(0, mIndicationBottomMargin - mIndicationBottomMarginAmbient, darkAmount)); @@ -841,8 +840,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void dozeTimeTick() { if (mDarkAmount == 1) { // Move indication every minute to avoid burn-in - final int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient; - mIndicationArea.setTranslationY(dozeTranslation + (float) Math.random() * 5); + int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient; + int burnInYOffset = (int) (-mBurnInYOffset + Math.random() * mBurnInYOffset * 2); + mIndicationArea.setTranslationY(dozeTranslation + burnInYOffset); } } 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/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 2a1f92f5edda..f8b79c61c430 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import static android.view.MotionEvent.ACTION_DOWN; import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK; +import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE; import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME; import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE; @@ -328,15 +329,15 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (shouldDeadZoneConsumeTouchEvents(event)) { - return true; - } + final boolean deadZoneConsumed = shouldDeadZoneConsumeTouchEvents(event); switch (event.getActionMasked()) { case ACTION_DOWN: int x = (int) event.getX(); int y = (int) event.getY(); mDownHitTarget = HIT_TARGET_NONE; - if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) { + if (deadZoneConsumed) { + mDownHitTarget = HIT_TARGET_DEAD_ZONE; + } else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) { mDownHitTarget = HIT_TARGET_BACK; } else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) { mDownHitTarget = HIT_TARGET_HOME; @@ -353,9 +354,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav @Override public boolean onTouchEvent(MotionEvent event) { - if (shouldDeadZoneConsumeTouchEvents(event)) { - return true; - } + shouldDeadZoneConsumeTouchEvents(event); if (mGestureHelper.onTouchEvent(event)) { return true; } @@ -764,7 +763,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav showSwipeUpUI ? mQuickStepAccessibilityDelegate : null); } - private void updateSlippery() { + public void updateSlippery() { setSlippery(!isQuickStepSwipeUpEnabled() || mPanelView.isFullyExpanded()); } 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..7e6abe95e226 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -47,6 +47,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.accessibility.AccessibilityManager; +import android.view.animation.Interpolator; import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; @@ -107,17 +108,20 @@ public class NotificationPanelView extends PanelView implements private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties() .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); private static final FloatProperty<NotificationPanelView> SET_DARK_AMOUNT_PROPERTY = - new FloatProperty<NotificationPanelView>("mDarkAmount") { + new FloatProperty<NotificationPanelView>("mInterpolatedDarkAmount") { + @Override public void setValue(NotificationPanelView object, float value) { - object.setDarkAmount(value); + object.setDarkAmount(value, object.mDarkInterpolator.getInterpolation(value)); } @Override public Float get(NotificationPanelView object) { - return object.mDarkAmount; + return object.mLinearDarkAmount; } }; + + private Interpolator mDarkInterpolator; private final PowerManager mPowerManager; private final AccessibilityManager mAccessibilityManager; @@ -221,6 +225,7 @@ public class NotificationPanelView extends PanelView implements private boolean mClosingWithAlphaFadeOut; private boolean mHeadsUpAnimatingAway; private boolean mLaunchingAffordance; + private boolean mAffordanceHasPreview; private FalsingManager mFalsingManager; private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; @@ -236,7 +241,18 @@ public class NotificationPanelView extends PanelView implements private int mIndicationBottomPadding; private int mAmbientIndicationBottomPadding; private boolean mIsFullWidth; - private float mDarkAmount; + + /** + * Current dark amount that follows regular interpolation curve of animation. + */ + private float mInterpolatedDarkAmount; + + /** + * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the + * interpolation curve is different. + */ + private float mLinearDarkAmount; + private float mDarkAmountTarget; private boolean mPulsing; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); @@ -391,7 +407,7 @@ public class NotificationPanelView extends PanelView implements false); addView(mKeyguardBottomArea, index); initBottomArea(); - setDarkAmount(mDarkAmount); + setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount); setKeyguardStatusViewVisibility(mStatusBarState, false, false); setKeyguardBottomAreaVisibility(mStatusBarState, false); @@ -505,7 +521,7 @@ public class NotificationPanelView extends PanelView implements getExpandedFraction(), totalHeight, mKeyguardStatusView.getHeight(), - mDarkAmount, + mInterpolatedDarkAmount, mStatusBar.isKeyguardCurrentlySecure(), mPulsing, mBouncerTop); @@ -1916,7 +1932,7 @@ public class NotificationPanelView extends PanelView implements if (view == null && mQsExpanded) { return; } - if (needsAnimation && mDarkAmount == 0) { + if (needsAnimation && mInterpolatedDarkAmount == 0) { mAnimateNextPositionUpdate = true; } ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone(); @@ -2489,7 +2505,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++) { @@ -2569,6 +2585,7 @@ public class NotificationPanelView extends PanelView implements } else { animate = false; } + mAffordanceHasPreview = mKeyguardBottomArea.getRightPreview() != null; mAffordanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL); } @@ -2614,6 +2631,13 @@ public class NotificationPanelView extends PanelView implements } /** + * Return true when a bottom affordance is launching an occluded activity with a splash screen. + */ + public boolean isLaunchingAffordanceWithPreview() { + return mLaunchingAffordance && mAffordanceHasPreview; + } + + /** * Whether the camera application can be launched for the camera launch gesture. * * @param keyguardIsShowing whether keyguard is being shown @@ -2718,31 +2742,40 @@ public class NotificationPanelView extends PanelView implements } mDarkAmountTarget = darkAmount; if (animate) { + if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) { + mDarkInterpolator = dozing + ? Interpolators.FAST_OUT_SLOW_IN + : Interpolators.TOUCH_RESPONSE_REVERSE; + } + mNotificationStackScroller.notifyDarkAnimationStart(dozing); mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount); - mDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP); + mDarkAnimator.setInterpolator(Interpolators.LINEAR); + mDarkAnimator.setDuration(mNotificationStackScroller.getDarkAnimationDuration(dozing)); mDarkAnimator.start(); } else { - setDarkAmount(darkAmount); + setDarkAmount(darkAmount, darkAmount); } } - private void setDarkAmount(float amount) { - mDarkAmount = amount; - mKeyguardStatusView.setDarkAmount(mDarkAmount); - mKeyguardBottomArea.setDarkAmount(mDarkAmount); + private void setDarkAmount(float linearAmount, float amount) { + mInterpolatedDarkAmount = amount; + mLinearDarkAmount = linearAmount; + mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount); + mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount); positionClockAndNotifications(); + mNotificationStackScroller.setDarkAmount(linearAmount, mInterpolatedDarkAmount); } 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) { @@ -2755,7 +2788,7 @@ public class NotificationPanelView extends PanelView implements public void dozeTimeTick() { mKeyguardStatusView.dozeTimeTick(); mKeyguardBottomArea.dozeTimeTick(); - if (mDarkAmount > 0) { + if (mInterpolatedDarkAmount > 0) { positionClockAndNotifications(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index c4d7e72c0d82..6f4a3cd82140 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -29,6 +29,7 @@ public abstract class PanelBar extends FrameLayout { private static final boolean SPEW = false; private boolean mBouncerShowing; private boolean mExpanded; + protected float mPanelFraction; public static final void LOG(String fmt, Object... args) { if (!DEBUG) return; @@ -77,6 +78,14 @@ public abstract class PanelBar extends FrameLayout { if (mPanel != null) mPanel.setImportantForAccessibility(important); } + public float getExpansionFraction() { + return mPanelFraction; + } + + public boolean isExpanded() { + return mExpanded; + } + private void updateVisibility() { mPanel.setVisibility(mExpanded || mBouncerShowing ? VISIBLE : INVISIBLE); } @@ -131,6 +140,7 @@ public abstract class PanelBar extends FrameLayout { if (SPEW) LOG("panelExpansionChanged: start state=%d", mState); PanelView pv = mPanel; mExpanded = expanded; + mPanelFraction = frac; updateVisibility(); // adjust any other panels that may be partially visible if (expanded) { 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..59863ecb1191 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -59,7 +59,6 @@ public class PhoneStatusBarView extends PanelBar { private final PhoneStatusBarTransitions mBarTransitions; private ScrimController mScrimController; private float mMinFraction; - private float mPanelFraction; private Runnable mHideExpandedRunnable = new Runnable() { @Override public void run() { @@ -269,7 +268,6 @@ public class PhoneStatusBarView extends PanelBar { @Override public void panelExpansionChanged(float frac, boolean expanded) { super.panelExpansionChanged(frac, expanded); - mPanelFraction = frac; updateScrimFraction(); if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) { mBar.getNavigationBarView().onPanelExpandedChange(expanded); @@ -331,30 +329,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/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java index 860b77e1b251..af1d220f46f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java @@ -22,20 +22,21 @@ import static com.android.systemui.Interpolators.ALPHA_IN; import static com.android.systemui.Interpolators.ALPHA_OUT; import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY; import static com.android.systemui.OverviewProxyService.TAG_OPS; +import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; -import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RadialGradient; import android.graphics.Rect; -import android.graphics.drawable.Drawable; +import android.graphics.Shader; import android.os.Handler; import android.os.RemoteException; import android.util.FloatProperty; @@ -54,7 +55,6 @@ import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.system.NavigationBarCompat; -import com.android.internal.graphics.ColorUtils; /** * Class to detect gestures on the navigation bar and implement quick scrub. @@ -65,6 +65,7 @@ public class QuickStepController implements GestureHelper { private static final int ANIM_IN_DURATION_MS = 150; private static final int ANIM_OUT_DURATION_MS = 134; private static final float TRACK_SCALE = 0.95f; + private static final float GRADIENT_WIDTH = .75f; private NavigationBarView mNavigationBarView; @@ -78,23 +79,22 @@ public class QuickStepController implements GestureHelper { private boolean mIsRTL; private float mTrackAlpha; private float mTrackScale = TRACK_SCALE; - private int mLightTrackColor; - private int mDarkTrackColor; private float mDarkIntensity; + private RadialGradient mHighlight; + private float mHighlightCenter; private AnimatorSet mTrackAnimator; private ButtonDispatcher mHitTarget; private View mCurrentNavigationBarView; private final Handler mHandler = new Handler(); private final Rect mTrackRect = new Rect(); - private final Drawable mTrackDrawable; private final OverviewProxyService mOverviewEventSender; private final int mTrackThickness; private final int mTrackEndPadding; private final Context mContext; private final Matrix mTransformGlobalMatrix = new Matrix(); private final Matrix mTransformLocalMatrix = new Matrix(); - private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator(); + private final Paint mTrackPaint = new Paint(); private final FloatProperty<QuickStepController> mTrackAlphaProperty = new FloatProperty<QuickStepController>("TrackAlpha") { @@ -155,7 +155,8 @@ public class QuickStepController implements GestureHelper { mOverviewEventSender = Dependency.get(OverviewProxyService.class); mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness); mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding); - mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate(); + mTrackPaint.setAntiAlias(true); + mTrackPaint.setDither(true); } public void setComponents(NavigationBarView navigationBarView) { @@ -184,6 +185,8 @@ public class QuickStepController implements GestureHelper { } private boolean handleTouchEvent(MotionEvent event) { + final boolean deadZoneConsumed = + mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE; if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled() && !mNavigationBarView.isQuickStepSwipeUpEnabled())) { return false; @@ -287,6 +290,8 @@ public class QuickStepController implements GestureHelper { } catch (RemoteException e) { Log.e(TAG, "Failed to send progress of quick scrub.", e); } + mHighlightCenter = x; + mNavigationBarView.invalidate(); } break; } @@ -302,7 +307,7 @@ public class QuickStepController implements GestureHelper { || action == MotionEvent.ACTION_UP)) { proxyMotionEvents(event); } - return mQuickScrubActive || mQuickStepStarted; + return mQuickScrubActive || mQuickStepStarted || deadZoneConsumed; } @Override @@ -310,18 +315,18 @@ public class QuickStepController implements GestureHelper { if (!mNavigationBarView.isQuickScrubEnabled()) { return; } - int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor, - mDarkTrackColor); - int colorAlpha = ColorUtils.setAlphaComponent(color, - (int) (Color.alpha(color) * mTrackAlpha)); - mTrackDrawable.setTint(colorAlpha); + mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha)); // Scale the track, but apply the inverse scale from the nav bar + final float radius = mTrackRect.height() / 2; canvas.save(); + float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right); + canvas.translate(translate, 0); canvas.scale(mTrackScale / mNavigationBarView.getScaleX(), 1f / mNavigationBarView.getScaleY(), mTrackRect.centerX(), mTrackRect.centerY()); - mTrackDrawable.draw(canvas); + canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top, + mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint); canvas.restore(); } @@ -346,12 +351,20 @@ public class QuickStepController implements GestureHelper { x2 = x1 + width - 2 * mTrackEndPadding; } mTrackRect.set(x1, y1, x2, y2); - mTrackDrawable.setBounds(mTrackRect); + updateHighlight(); } @Override public void onDarkIntensityChange(float intensity) { + final float oldIntensity = mDarkIntensity; mDarkIntensity = intensity; + + // When in quick scrub, invalidate gradient if changing intensity from black to white and + // vice-versa + if (mNavigationBarView.isQuickScrubEnabled() + && Math.round(intensity) != Math.round(oldIntensity)) { + updateHighlight(); + } mNavigationBarView.invalidate(); } @@ -408,10 +421,8 @@ public class QuickStepController implements GestureHelper { private void startQuickScrub() { if (!mQuickScrubActive) { + updateHighlight(); mQuickScrubActive = true; - mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light); - mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark); - ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this, PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f), PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f)); @@ -424,6 +435,9 @@ public class QuickStepController implements GestureHelper { mTrackAnimator.playTogether(trackAnimator, navBarAnimator); mTrackAnimator.start(); + // Disable slippery for quick scrub to not cancel outside the nav bar + mNavigationBarView.updateSlippery(); + try { mOverviewEventSender.getProxy().onQuickScrubStart(); if (DEBUG_OVERVIEW_PROXY) { @@ -483,6 +497,25 @@ public class QuickStepController implements GestureHelper { mQuickScrubActive = false; mAllowGestureDetection = false; mCurrentNavigationBarView = null; + updateHighlight(); + } + + private void updateHighlight() { + if (mTrackRect.isEmpty()) { + return; + } + int colorBase, colorGrad; + if (mDarkIntensity > 0.5f) { + colorBase = mContext.getColor(R.color.quick_step_track_background_background_dark); + colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_dark); + } else { + colorBase = mContext.getColor(R.color.quick_step_track_background_background_light); + colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_light); + } + mHighlight = new RadialGradient(0, mTrackRect.height() / 2, + mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase, + Shader.TileMode.CLAMP); + mTrackPaint.setShader(mHighlight); } private boolean proxyMotionEvents(MotionEvent event) { 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..61f0e1cb29c7 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,18 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo updateScrims(); } + public void setHasBackdrop(boolean hasBackdrop) { + for (ScrimState state : ScrimState.values()) { + state.setHasBackdrop(hasBackdrop); + } + } + + public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) { + for (ScrimState state : ScrimState.values()) { + state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview); + } + } + 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..19015fcdacf7 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; } @@ -147,8 +144,9 @@ public enum ScrimState { mCurrentBehindAlpha = 0; mCurrentInFrontAlpha = 0; mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION; + mAnimateChange = !mLaunchingAffordanceWithPreview; - if (previousState == ScrimState.AOD || previousState == ScrimState.PULSING) { + if (previousState == ScrimState.AOD) { // Fade from black to transparent when coming directly from AOD updateScrimColor(mScrimInFront, 1, Color.BLACK); updateScrimColor(mScrimBehind, 1, Color.BLACK); @@ -178,8 +176,9 @@ public enum ScrimState { DozeParameters mDozeParameters; boolean mDisplayRequiresBlanking; boolean mWallpaperSupportsAmbientMode; - KeyguardUpdateMonitor mKeyguardUpdateMonitor; int mIndex; + boolean mHasBackdrop; + boolean mLaunchingAffordanceWithPreview; ScrimState(int index) { mIndex = index; @@ -190,7 +189,6 @@ public enum ScrimState { mScrimBehind = scrimBehind; mDozeParameters = dozeParameters; mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking(); - mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(scrimInFront.getContext()); } public void prepare(ScrimState previousState) { @@ -253,7 +251,15 @@ public enum ScrimState { mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode; } + public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) { + mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview; + } + 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..78634656d866 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -52,6 +52,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.StatusBarManager; import android.app.TaskStackBuilder; +import android.app.UiModeManager; import android.app.WallpaperColors; import android.app.WallpaperInfo; import android.app.WallpaperManager; @@ -326,6 +327,12 @@ public class StatusBar extends SystemUI implements DemoMode, /** If true, the lockscreen will show a distinct wallpaper */ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; + /** Whether to force dark theme if Configuration.UI_MODE_NIGHT_YES. */ + private static final boolean DARK_THEME_IN_NIGHT_MODE = true; + + /** Whether to switch the device into night mode in battery saver. */ + private static final boolean NIGHT_MODE_IN_BATTERY_SAVER = true; + /** * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode * won't draw anything and uninitialized memory will show through @@ -607,6 +614,12 @@ public class StatusBar extends SystemUI implements DemoMode, maybeEscalateHeadsUp(); } } + + @Override + public void onStrongAuthStateChanged(int userId) { + super.onStrongAuthStateChanged(userId); + mEntryManager.updateNotifications(); + } }; private NavigationBarFragment mNavigationBar; @@ -823,23 +836,31 @@ 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) -> { CollapsedStatusBarFragment statusBarFragment = (CollapsedStatusBarFragment) fragment; statusBarFragment.initNotificationIconArea(mNotificationIconAreaController); + PhoneStatusBarView oldStatusBarView = mStatusBarView; mStatusBarView = (PhoneStatusBarView) fragment.getView(); mStatusBarView.setBar(this); mStatusBarView.setPanel(mNotificationPanel); mStatusBarView.setScrimController(mScrimController); mStatusBarView.setBouncerShowing(mBouncerShowing); + if (oldStatusBarView != null) { + float fraction = oldStatusBarView.getExpansionFraction(); + boolean expanded = oldStatusBarView.isExpanded(); + mStatusBarView.panelExpansionChanged(fraction, expanded); + } if (mHeadsUpAppearanceController != null) { // This view is being recreated, let's destroy the old one mHeadsUpAppearanceController.destroy(); } mHeadsUpAppearanceController = new HeadsUpAppearanceController( mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow); + mStatusBarWindow.setStatusBarView(mStatusBarView); setAreThereNotifications(); checkBarModes(); }).getFragmentManager() @@ -917,6 +938,10 @@ public class StatusBar extends SystemUI implements DemoMode, if (mDozeServiceHost != null) { mDozeServiceHost.firePowerSaveChanged(isPowerSave); } + if (NIGHT_MODE_IN_BATTERY_SAVER) { + mContext.getSystemService(UiModeManager.class).setNightMode( + isPowerSave ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO); + } } @Override @@ -1645,8 +1670,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 +1691,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 +1742,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 @@ -3112,6 +3139,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void onConfigChanged(Configuration newConfig) { updateResources(); updateDisplaySize(); // populates mDisplayMetrics + updateTheme(); if (DEBUG) { Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); @@ -3846,13 +3874,18 @@ 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 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM); - final boolean useDarkTheme = systemColors != null + final boolean wallpaperWantsDarkTheme = systemColors != null && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; + final Configuration config = mContext.getResources().getConfiguration(); + final boolean nightModeWantsDarkTheme = DARK_THEME_IN_NIGHT_MODE + && (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + final boolean useDarkTheme = wallpaperWantsDarkTheme || nightModeWantsDarkTheme; if (isUsingDarkTheme() != useDarkTheme) { mUiOffloadThread.submit(() -> { try { @@ -4686,7 +4719,6 @@ public class StatusBar extends SystemUI implements DemoMode, boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD || mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; - final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn(); // When in wake-and-unlock we may not have received a change to mState // but we still should not be dozing, manually set to false. if (mFingerprintUnlockController.getMode() == @@ -4695,7 +4727,7 @@ public class StatusBar extends SystemUI implements DemoMode, } if (mDozing != dozing) { mDozing = dozing; - mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn); + mKeyguardViewMediator.setAodShowing(mDozing); mStatusBarWindowManager.setDozing(mDozing); mStatusBarKeyguardViewManager.setDozing(mDozing); if (mAmbientIndicationContainer instanceof DozeReceiver) { @@ -4720,6 +4752,10 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController.setExpansionAffectsAlpha( !mFingerprintUnlockController.isFingerprintUnlock()); + boolean launchingAffordanceWithPreview = + mNotificationPanel.isLaunchingAffordanceWithPreview(); + mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview); + if (mBouncerShowing) { // Bouncer needs the front scrim when it's on top of an activity, // tapping on a notification, editing QS or being dismissed by @@ -4729,7 +4765,8 @@ public class StatusBar extends SystemUI implements DemoMode, || mStatusBarKeyguardViewManager.isFullscreenBouncer() ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER; mScrimController.transitionTo(state); - } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) { + } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn + || launchingAffordanceWithPreview) { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } else if (mBrightnessMirrorVisible) { mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR); @@ -4822,6 +4859,7 @@ public class StatusBar extends SystemUI implements DemoMode, } private void setPulsing(boolean pulsing) { + mKeyguardViewMediator.setPulsing(pulsing); mNotificationPanel.setPulsing(pulsing); mVisualStabilityManager.setPulsing(pulsing); mIgnoreTouchWhilePulsing = false; 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..ff4f215b482f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -34,7 +34,6 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Path; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -46,11 +45,9 @@ import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; -import android.util.FloatProperty; import android.util.Log; import android.util.MathUtils; import android.util.Pair; -import android.util.Property; import android.view.ContextThemeWrapper; import android.view.InputDevice; import android.view.MotionEvent; @@ -101,6 +98,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 +138,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; @@ -375,20 +372,22 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mScrollable; private View mForcedScroll; private View mNeedingPulseAnimation; - private float mDarkAmount = 0f; - private static final Property<NotificationStackScrollLayout, Float> DARK_AMOUNT = - new FloatProperty<NotificationStackScrollLayout>("darkAmount") { - @Override - public void setValue(NotificationStackScrollLayout object, float value) { - object.setDarkAmount(value); - } - @Override - public Float get(NotificationStackScrollLayout object) { - return object.getDarkAmount(); - } - }; - private ObjectAnimator mDarkAmountAnimator; + /** + * @see #setDarkAmount(float, float) + */ + private float mInterpolatedDarkAmount = 0f; + + /** + * @see #setDarkAmount(float, float) + */ + private float mLinearDarkAmount = 0f; + + /** + * How fast the background scales in the X direction as a factor of the Y expansion. + */ + private float mBackgroundXFactor = 1f; + private boolean mUsingLightTheme; private boolean mQsExpanded; private boolean mForwardScrollable; @@ -416,6 +415,10 @@ 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; + + private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -532,10 +535,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 @@ -545,16 +554,16 @@ public class NotificationStackScrollLayout extends ViewGroup canvas.drawRect(darkLeft, darkTop, darkRight, darkBottom, mBackgroundPaint); } } else { - float inverseDark = 1 - mDarkAmount; - float yProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(inverseDark); - float xProgress = Interpolators.FAST_OUT_SLOW_IN - .getInterpolation(inverseDark * 2f); + float yProgress = 1 - mInterpolatedDarkAmount; + float xProgress = mDarkXInterpolator.getInterpolation( + (1 - mLinearDarkAmount) * mBackgroundXFactor); mBackgroundAnimationRect.set( (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress), (int) MathUtils.lerp(darkTop, lockScreenTop, yProgress), (int) MathUtils.lerp(darkRight, lockScreenRight, xProgress), (int) MathUtils.lerp(darkBottom, lockScreenBottom, yProgress)); + if (!mAmbientState.isDark() || mFirstVisibleBackgroundChild != null) { canvas.drawRoundRect(mBackgroundAnimationRect.left, mBackgroundAnimationRect.top, mBackgroundAnimationRect.right, mBackgroundAnimationRect.bottom, @@ -572,14 +581,15 @@ public class NotificationStackScrollLayout extends ViewGroup float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount); - alpha *= 1f - mDarkAmount; + alpha *= 1f - mInterpolatedDarkAmount; // We need to manually blend in the background color. int scrimColor = mScrimController.getBackgroundColor(); int awakeColor = ColorUtils.blendARGB(scrimColor, mBgColor, alpha); // Interpolate between semi-transparent notification panel background color // and white AOD separator. - float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation(mDarkAmount); + float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation( + mInterpolatedDarkAmount); int color = ColorUtils.blendARGB(awakeColor, Color.WHITE, colorInterpolation); if (mCachedBackgroundColor != color) { @@ -723,7 +733,8 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updateAlgorithmHeightAndPadding() { - mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, mDarkAmount); + mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, + mInterpolatedDarkAmount); mAmbientState.setLayoutHeight(getLayoutHeight()); updateAlgorithmLayoutMinHeight(); mAmbientState.setTopPadding(mTopPadding); @@ -948,7 +959,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void updateClipping() { - boolean animatingClipping = mDarkAmount > 0 && mDarkAmount < 1; + boolean animatingClipping = mInterpolatedDarkAmount > 0 && mInterpolatedDarkAmount < 1; boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode && !mHeadsUpAnimatingAway; if (mIsClipped != clipped) { @@ -2041,11 +2052,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 +2155,6 @@ public class NotificationStackScrollLayout extends ViewGroup return count; } - public int getContentHeight() { - return mContentHeight; - } - private void updateContentHeight() { int height = 0; float previousPaddingRequest = mPaddingBetweenElements; @@ -2213,7 +2218,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); @@ -2410,7 +2419,7 @@ public class NotificationStackScrollLayout extends ViewGroup return; } - final boolean awake = mDarkAmount != 0 || mAmbientState.isDark(); + final boolean awake = mInterpolatedDarkAmount != 0 || mAmbientState.isDark(); mScrimController.setExcludedBackgroundArea( mFadingOut || mParentNotFullyVisible || awake || mIsClipped ? null : mCurrentBounds); @@ -3403,7 +3412,6 @@ public class NotificationStackScrollLayout extends ViewGroup .animateY(mShelf)); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); - startDarkAmountAnimation(); } mDarkNeedsAnimation = false; } @@ -3979,11 +3987,8 @@ public class NotificationStackScrollLayout extends ViewGroup if (animate && mAnimationsEnabled) { mDarkNeedsAnimation = true; mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); - mNeedsAnimation = true; + mNeedsAnimation = true; } else { - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); - } setDarkAmount(dark ? 1f : 0f); updateBackground(); } @@ -3993,8 +3998,13 @@ public class NotificationStackScrollLayout extends ViewGroup notifyHeightChangeListener(mShelf); } - private void updateAntiBurnInTranslation() { - setTranslationX(mAntiBurnInOffsetX * mDarkAmount); + private void updatePanelTranslation() { + setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount); + } + + public void setVerticalPanelTranslation(float verticalPanelTranslation) { + mVerticalPanelTranslation = verticalPanelTranslation; + updatePanelTranslation(); } /** @@ -4008,42 +4018,57 @@ public class NotificationStackScrollLayout extends ViewGroup } private void setDarkAmount(float darkAmount) { - mDarkAmount = darkAmount; + setDarkAmount(darkAmount, darkAmount); + } + + /** + * Sets the current dark amount. + * + * @param linearDarkAmount The dark amount that follows linear interpoloation in the animation, + * i.e. animates from 0 to 1 or vice-versa in a linear manner. + * @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the + * animation curve. + */ + public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) { + mLinearDarkAmount = linearDarkAmount; + mInterpolatedDarkAmount = interpolatedDarkAmount; boolean wasFullyDark = mAmbientState.isFullyDark(); - mAmbientState.setDarkAmount(darkAmount); - if (mAmbientState.isFullyDark() != wasFullyDark) { + mAmbientState.setDarkAmount(interpolatedDarkAmount); + 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(); } - public float getDarkAmount() { - return mDarkAmount; + public void notifyDarkAnimationStart(boolean dark) { + // 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 (mInterpolatedDarkAmount == 0 || mInterpolatedDarkAmount == 1) { + mBackgroundXFactor = dark ? 1.8f : 1.5f; + mDarkXInterpolator = dark + ? Interpolators.FAST_OUT_SLOW_IN_REVERSE + : Interpolators.FAST_OUT_SLOW_IN; + } } - 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() { - @Override - public void onAnimationEnd(Animator animation) { - mDarkAmountAnimator = null; - } - }); - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); + public long getDarkAnimationDuration(boolean dark) { + long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP; + // Longer animation when sleeping with more than 1 notification + if (dark && getNotGoneChildCount() > 2) { + duration *= 1.2f; } - mDarkAmountAnimator = darkAnimator; - mDarkAmountAnimator.start(); + return duration; } private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { @@ -4572,7 +4597,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 +4643,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 +5060,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 +5130,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/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml index 80d8066959af..9254b4d65b50 100644 --- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml @@ -37,6 +37,8 @@ @right </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml index ca261f98cfae..80c997a46264 100644 --- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml @@ -49,6 +49,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml index c22b2e778ff1..6fb3c7f51e26 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml @@ -40,6 +40,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml index 401e09211ae7..7c29ffb92f4e 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml @@ -40,6 +40,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml index f328b83c1cbf..5fb8b9e241b8 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml @@ -40,6 +40,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 4328d94275e9..143fa8634333 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -6116,7 +6116,21 @@ message MetricsEvent { // OS: P FIELD_AUTOFILL_SESSION_ID = 1456; + // NOTIFICATION_SINCE_INTERRUPTION_MILLIS added to P + // NOTIFICATION_INTERRUPTION added to P + // ---- End P Constants, all P constants go above this line ---- + + // Time since this notification last interrupted (visibly or audible) the user + NOTIFICATION_SINCE_INTERRUPTION_MILLIS = 1500; + + // OPEN: Notification interrupted the user, either audibly or visually. + // Tagged data: NOTIFICATION_SINCE_INTERRUPTION_MILLIS + // CATEGORY: NOTIFICATION + NOTIFICATION_INTERRUPTION = 1501; + + // ---- End Q Constants, all Q constants go above this line ---- + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index a9a14cad7f7d..fba639c3fc4a 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -212,6 +212,10 @@ message SystemMessage { // Package: android NOTE_AUTO_SAVER_SUGGESTION = 49; + // Notify the user that their softap config preference has changed. + // Package: android + NOTE_SOFTAP_CONFIG_CHANGED = 50; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release 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..f58f717878f1 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1658,7 +1658,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // 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()) { + if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty() + && !mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) { + if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "adding to waiting visible activity=" + r + + " existing=" + mStackSupervisor.mActivitiesWaitingForVisibleActivity); mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index e034b824dc50..c520101d3ff4 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1634,6 +1634,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to * {@code true} if config changed. * @param deferResume Whether to defer resume while updating config. + * @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched + * because of configuration update. */ boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId, boolean markFrozenIfConfigChanged, boolean deferResume) { @@ -1644,6 +1646,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, false /* preserveWindows */, false /* notifyClients */); + if (displayId == INVALID_DISPLAY) { + // The caller didn't provide a valid display id, skip updating config. + return true; + } + // Force-update the orientation from the WindowManager, since we need the true configuration // to send to the client now. final Configuration config = mWindowManager.updateOrientationFromAppTokens( @@ -3930,6 +3937,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stops = new ArrayList<>(); } stops.add(s); + + // Make sure to remove it in all cases in case we entered this block with + // shouldSleepOrShutDown + mActivitiesWaitingForVisibleActivity.remove(s); mStoppingActivities.remove(activityNdx); } } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 49fa902d161d..9eb22d717850 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -543,14 +543,25 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs; final long scanTimeMs = latest.mControllerScanTimeMs - lastScanMs; - if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0) { + if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0 || idleTimeMs < 0) { // The stats were reset by the WiFi system (which is why our delta is negative). - // Returns the unaltered stats. - delta.mControllerEnergyUsed = latest.mControllerEnergyUsed; - delta.mControllerRxTimeMs = latest.mControllerRxTimeMs; - delta.mControllerTxTimeMs = latest.mControllerTxTimeMs; - delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs; - delta.mControllerScanTimeMs = latest.mControllerScanTimeMs; + // Returns the unaltered stats. The total on time should not exceed the time + // duartion between reports. + final long totalOnTimeMs = latest.mControllerTxTimeMs + latest.mControllerRxTimeMs + + latest.mControllerIdleTimeMs; + if (totalOnTimeMs <= timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) { + delta.mControllerEnergyUsed = latest.mControllerEnergyUsed; + delta.mControllerRxTimeMs = latest.mControllerRxTimeMs; + delta.mControllerTxTimeMs = latest.mControllerTxTimeMs; + delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs; + delta.mControllerScanTimeMs = latest.mControllerScanTimeMs; + } else { + delta.mControllerEnergyUsed = 0; + delta.mControllerRxTimeMs = 0; + delta.mControllerTxTimeMs = 0; + delta.mControllerIdleTimeMs = 0; + delta.mControllerScanTimeMs = 0; + } Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta); } else { final long totalActiveTimeMs = txTimeMs + rxTimeMs; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 0b9832d90f7d..592453fb278b 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, @@ -3811,6 +3811,10 @@ public class AudioService extends IAudioService.Stub int delay = checkSendBecomingNoisyIntent( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState, AudioSystem.DEVICE_NONE); + final String addr = btDevice == null ? "null" : btDevice.getAddress(); + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "A2DP service connected: device addr=" + addr + + " state=" + state)); queueMsgUnderWakeLock(mAudioHandler, MSG_SET_A2DP_SINK_CONNECTION_STATE, state, @@ -4521,13 +4525,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); } } @@ -4666,7 +4678,14 @@ public class AudioService extends IAudioService.Stub public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state + // only querying address as this is the only readily available field on the device + + " addr=" + device.getAddress() + + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent + + " vol=" + a2dpVolume)); if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) { + mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored")); return 0; } return setBluetoothA2dpDeviceConnectionStateInt( @@ -4689,6 +4708,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 +5623,7 @@ public class AudioService extends IAudioService.Stub synchronized (mConnectedDevices) { makeA2dpDeviceUnavailableNow( (String) msg.obj ); } + mAudioEventWakeLock.release(); break; case MSG_SET_FORCE_USE: @@ -5611,7 +5638,7 @@ public class AudioService extends IAudioService.Stub case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: { WiredDeviceConnectionState connectState = (WiredDeviceConnectionState)msg.obj; - mWiredDevLogger.log(new WiredDevConnectEvent(connectState)); + mDeviceLogger.log(new WiredDevConnectEvent(connectState)); onSetWiredDeviceConnectionState(connectState.mType, connectState.mState, connectState.mAddress, connectState.mName, connectState.mCaller); mAudioEventWakeLock.release(); @@ -5827,6 +5854,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 +5866,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 +5880,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 +5957,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 +5995,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); } @@ -6056,10 +6093,14 @@ public class AudioService extends IAudioService.Stub if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "onBluetoothA2dpDeviceConfigChange addr=" + address)); int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; synchronized (mConnectedDevices) { if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) { + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "A2dp config change ignored")); return; } final String key = makeDeviceListKey(device, address); @@ -6177,17 +6218,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; } @@ -7166,19 +7196,20 @@ public class AudioService extends IAudioService.Stub //========================================================================================== // AudioService logging and dumpsys //========================================================================================== - final int LOG_NB_EVENTS_PHONE_STATE = 20; - final int LOG_NB_EVENTS_WIRED_DEV_CONNECTION = 30; - final int LOG_NB_EVENTS_FORCE_USE = 20; - final int LOG_NB_EVENTS_VOLUME = 40; - final int LOG_NB_EVENTS_DYN_POLICY = 10; + static final int LOG_NB_EVENTS_PHONE_STATE = 20; + static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30; + static final int LOG_NB_EVENTS_FORCE_USE = 20; + static final int LOG_NB_EVENTS_VOLUME = 40; + static final int LOG_NB_EVENTS_DYN_POLICY = 10; final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE, "phone state (logged after successfull call to AudioSystem.setPhoneState(int))"); - final private AudioEventLogger mWiredDevLogger = new AudioEventLogger( - LOG_NB_EVENTS_WIRED_DEV_CONNECTION, - "wired device connection (logged before onSetWiredDeviceConnectionState() is executed)" - ); + // logs for wired + A2DP device connections: + // - wired: logged before onSetWiredDeviceConnectionState() is executed + // - A2DP: logged at reception of method call + final private AudioEventLogger mDeviceLogger = new AudioEventLogger( + LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP device connection"); final private AudioEventLogger mForceUseLogger = new AudioEventLogger( LOG_NB_EVENTS_FORCE_USE, @@ -7267,7 +7298,7 @@ public class AudioService extends IAudioService.Stub pw.println("\nEvent logs:"); mModeLogger.dump(pw); pw.println("\n"); - mWiredDevLogger.dump(pw); + mDeviceLogger.dump(pw); pw.println("\n"); mForceUseLogger.dump(pw); pw.println("\n"); 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/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index b9a279ad13ea..21ae048e1d75 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -31,8 +31,6 @@ import android.os.Looper; import android.os.PowerManager; import android.os.SystemProperties; import android.os.Trace; -import android.text.TextUtils; -import android.util.PathParser; import android.util.Slog; import android.util.SparseArray; import android.view.Display; @@ -404,8 +402,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND; } - mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width, - mInfo.height); + mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res, + mInfo.width, mInfo.height); mInfo.type = Display.TYPE_BUILT_IN; mInfo.densityDpi = (int)(phys.density * 160 + 0.5f); mInfo.xDpi = phys.xDpi; 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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 36b04fcd6108..c6a871217ebd 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -955,12 +955,18 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSeparateChallengeLock") private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled, String managedUserPassword) { + final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId); - if (enabled) { - mStorage.removeChildProfileLock(userId); - removeKeystoreProfileKey(userId); - } else { - tieManagedProfileLockIfNecessary(userId, managedUserPassword); + try { + if (enabled) { + mStorage.removeChildProfileLock(userId); + removeKeystoreProfileKey(userId); + } else { + tieManagedProfileLockIfNecessary(userId, managedUserPassword); + } + } catch (IllegalStateException e) { + setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, old, userId); + throw e; } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0897b8a52ad6..c1112f7ec2c9 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -329,6 +329,8 @@ public class NotificationManagerService extends SystemService { private long[] mFallbackVibrationPattern; private boolean mUseAttentionLight; + boolean mHasLight = true; + boolean mLightEnabled; boolean mSystemReady; private boolean mDisableNotificationEffects; @@ -343,9 +345,9 @@ public class NotificationManagerService extends SystemService { private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; // for enabling and disabling notification pulse behavior - private boolean mScreenOn = true; + boolean mScreenOn = true; protected boolean mInCall = false; - private boolean mNotificationPulseEnabled; + boolean mNotificationPulseEnabled; private Uri mInCallNotificationUri; private AudioAttributes mInCallNotificationAudioAttributes; @@ -1195,7 +1197,8 @@ public class NotificationManagerService extends SystemService { ContentResolver resolver = getContext().getContentResolver(); if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { boolean pulseEnabled = Settings.System.getIntForUser(resolver, - Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0; + Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) + != 0; if (mNotificationPulseEnabled != pulseEnabled) { mNotificationPulseEnabled = pulseEnabled; updateNotificationPulse(); @@ -1457,6 +1460,8 @@ public class NotificationManagerService extends SystemService { mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume); mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); + mHasLight = + resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed); // Don't start allowing notifications until the setup wizard has run once. // After that, including subsequent boots, init with notifications turned on. @@ -3828,6 +3833,7 @@ public class NotificationManagerService extends SystemService { pw.println(" "); } pw.println(" mUseAttentionLight=" + mUseAttentionLight); + pw.println(" mHasLight=" + mHasLight); pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); @@ -4525,6 +4531,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 +4577,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)) { @@ -4825,8 +4831,7 @@ public class NotificationManagerService extends SystemService { // light // release the light boolean wasShowLights = mLights.remove(key); - if (record.getLight() != null && aboveThreshold - && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) { + if (canShowLightsLocked(record, aboveThreshold)) { mLights.add(key); updateLightsLocked(); if (mUseAttentionLight) { @@ -4837,7 +4842,19 @@ public class NotificationManagerService extends SystemService { updateLightsLocked(); } if (buzz || beep || blink) { - record.setInterruptive(true); + // Ignore summary updates because we don't display most of the information. + if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) { + if (DEBUG_INTERRUPTIVENESS) { + Log.v(TAG, "INTERRUPTIVENESS: " + + record.getKey() + " is not interruptive: summary"); + } + } else { + if (DEBUG_INTERRUPTIVENESS) { + Log.v(TAG, "INTERRUPTIVENESS: " + + record.getKey() + " is interruptive: alerted"); + } + record.setInterruptive(true); + } MetricsLogger.action(record.getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_ALERT) .setType(MetricsEvent.TYPE_OPEN) @@ -4847,11 +4864,49 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") + boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) { + // device lacks light + if (!mHasLight) { + return false; + } + // user turned lights off globally + if (!mNotificationPulseEnabled) { + return false; + } + // the notification/channel has no light + if (record.getLight() == null) { + return false; + } + // unimportant notification + if (!aboveThreshold) { + return false; + } + // suppressed due to DND + if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) { + return false; + } + // Suppressed because it's a silent update + final Notification notification = record.getNotification(); + if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { + return false; + } + // Suppressed because another notification in its group handles alerting + if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) { + return false; + } + // not if in call or the screen's on + if (mInCall || mScreenOn) { + return false; + } + + return true; + } + + @GuardedBy("mNotificationLock") boolean shouldMuteNotificationLocked(final NotificationRecord record) { // Suppressed because it's a silent update final Notification notification = record.getNotification(); - if(record.isUpdate - && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { + if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { return true; } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 0f3f44eae2d3..75b9f1311b75 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; @@ -127,6 +128,11 @@ public final class NotificationRecord { // The most recent update time, or the creation time if no updates. private long mUpdateTimeMs; + // The most recent interruption time, or the creation time if no updates. Differs from the + // above value because updates are filtered based on whether they actually interrupted the + // user + private long mInterruptionTimeMs; + // Is this record an update of an old record? public boolean isUpdate; private int mPackagePriority; @@ -174,10 +180,12 @@ 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(); mUpdateTimeMs = mCreationTimeMs; + mInterruptionTimeMs = mCreationTimeMs; mContext = context; stats = new NotificationUsageStats.SingleNotificationStats(); mChannel = channel; @@ -523,6 +531,7 @@ public final class NotificationRecord { pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs); pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs); pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs); + pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs); pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects); if (mPreChannelsNotification) { pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x", @@ -784,6 +793,10 @@ public final class NotificationRecord { return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs); } + public int getInterruptionMs(long now) { + return (int) (now - mInterruptionTimeMs); + } + /** * Set the visibility of the notification. */ @@ -842,7 +855,7 @@ public final class NotificationRecord { public void setSeen() { mStats.setSeen(); if (mTextChanged) { - mIsInterruptive = true; + setInterruptive(true); } } @@ -938,6 +951,17 @@ public final class NotificationRecord { public void setInterruptive(boolean interruptive) { mIsInterruptive = interruptive; + final long now = System.currentTimeMillis(); + mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs; + + if (interruptive) { + MetricsLogger.action(getLogMaker() + .setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION) + .setType(MetricsEvent.TYPE_OPEN) + .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS, + getInterruptionMs(now))); + MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now)); + } } public void setTextChanged(boolean textChanged) { @@ -1036,16 +1060,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 +1083,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 +1105,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); @@ -1112,7 +1138,9 @@ public final class NotificationRecord { sbn.getNotification().isGroupSummary() ? 1 : 0) .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now)) .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now)) - .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now)); + .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now)) + .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS, + getInterruptionMs(now)); } public LogMaker getLogMaker() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1b8c2cc8793e..c2d679858925 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -13967,6 +13967,68 @@ public class PackageManagerService extends IPackageManager.Stub return false; } + @Override + public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) { + enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled"); + synchronized (mPackages) { + final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); + if (pkgSetting == null || !pkgSetting.isSystem()) { + return; + } + PackageParser.Package pkg = pkgSetting.pkg; + if (pkg != null && pkg.applicationInfo != null) { + pkg.applicationInfo.hiddenUntilInstalled = hidden; + } + final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName); + if (disabledPs == null) { + return; + } + pkg = disabledPs.pkg; + if (pkg != null && pkg.applicationInfo != null) { + pkg.applicationInfo.hiddenUntilInstalled = hidden; + } + } + } + + @Override + public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) { + enforceSystemOrPhoneCaller("setSystemAppInstallState"); + synchronized (mPackages) { + final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); + // The target app should always be in system + if (pkgSetting == null || !pkgSetting.isSystem()) { + return false; + } + // Check if the install state is the same + if (pkgSetting.getInstalled(userId) == installed) { + return false; + } + } + + final long callingId = Binder.clearCallingIdentity(); + try { + if (installed) { + // install the app from uninstalled state + installExistingPackageAsUser( + packageName, + userId, + 0 /*installFlags*/, + PackageManager.INSTALL_REASON_DEVICE_SETUP); + return true; + } + + // uninstall the app from installed state + deletePackageVersioned( + new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), + new LegacyPackageDeleteObserver(null).getBinder(), + userId, + PackageManager.DELETE_SYSTEM_APP); + return true; + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { final PackageRemovedInfo info = new PackageRemovedInfo(this); @@ -14031,10 +14093,16 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int installExistingPackageAsUser(String packageName, int userId, int installFlags, int installReason) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, - null); - PackageSetting pkgSetting; final int callingUid = Binder.getCallingUid(); + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES) + != PackageManager.PERMISSION_GRANTED + && mContext.checkCallingOrSelfPermission( + android.Manifest.permission.INSTALL_EXISTING_PACKAGES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Neither user " + callingUid + " nor current process has " + + android.Manifest.permission.INSTALL_PACKAGES + "."); + } + PackageSetting pkgSetting; mPermissionManager.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, true /* checkShell */, "installExistingPackage for user " + userId); @@ -14178,7 +14246,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 +14401,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/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 5177995a8353..a7e38301bb40 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4120,7 +4120,8 @@ public final class Settings { continue; } final boolean shouldInstall = ps.isSystem() && - !ArrayUtils.contains(disallowedPackages, ps.name); + !ArrayUtils.contains(disallowedPackages, ps.name) && + !ps.pkg.applicationInfo.hiddenUntilInstalled; // Only system apps are initially installed. ps.setInstalled(shouldInstall, userHandle); if (!shouldInstall) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 599e5a573437..b9c304890420 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -132,6 +132,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Predicate; @@ -1573,6 +1574,24 @@ public class ShortcutService extends IShortcutService.Stub { "Ephemeral apps can't use ShortcutManager"); } + private void verifyShortcutInfoPackage(String callerPackage, ShortcutInfo si) { + if (si == null) { + return; + } + if (!Objects.equals(callerPackage, si.getPackage())) { + android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, ""); + throw new SecurityException("Shortcut package name mismatch"); + } + } + + private void verifyShortcutInfoPackages( + String callerPackage, List<ShortcutInfo> list) { + final int size = list.size(); + for (int i = 0; i < size; i++) { + verifyShortcutInfoPackage(callerPackage, list.get(i)); + } + } + // Overridden in unit tests to execute r synchronously. void injectPostToHandler(Runnable r) { mHandler.post(r); @@ -1720,6 +1739,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + verifyShortcutInfoPackages(packageName, newShortcuts); final int size = newShortcuts.size(); final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( @@ -1774,6 +1794,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + verifyShortcutInfoPackages(packageName, newShortcuts); final int size = newShortcuts.size(); final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( @@ -1859,6 +1880,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + verifyShortcutInfoPackages(packageName, newShortcuts); final int size = newShortcuts.size(); final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( @@ -1921,6 +1943,7 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkNotNull(shortcut); Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); verifyCaller(packageName, userId); + verifyShortcutInfoPackage(packageName, shortcut); final Intent ret; synchronized (mLock) { @@ -1942,6 +1965,7 @@ public class ShortcutService extends IShortcutService.Stub { private boolean requestPinItem(String packageName, int userId, ShortcutInfo shortcut, AppWidgetProviderInfo appWidget, Bundle extras, IntentSender resultIntent) { verifyCaller(packageName, userId); + verifyShortcutInfoPackage(packageName, shortcut); final boolean ret; synchronized (mLock) { 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/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java index 4e7fb969f398..e139ab86775d 100644 --- a/services/core/java/com/android/server/slice/PinnedSliceState.java +++ b/services/core/java/com/android/server/slice/PinnedSliceState.java @@ -154,8 +154,8 @@ public class PinnedSliceState { } ContentProviderClient getClient() { - ContentProviderClient client = - mService.getContext().getContentResolver().acquireContentProviderClient(mUri); + ContentProviderClient client = mService.getContext().getContentResolver() + .acquireUnstableContentProviderClient(mUri); if (client == null) return null; client.setDetectNotResponding(SLICE_TIMEOUT); return client; 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..2887e5ef9061 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()); @@ -1252,11 +1253,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo cutout, mInitialDisplayWidth, mInitialDisplayHeight); } final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); - final Path bounds = cutout.getBounds().getBoundaryPath(); + final List<Rect> bounds = WmDisplayCutout.computeSafeInsets( + cutout, mInitialDisplayWidth, mInitialDisplayHeight) + .getDisplayCutout().getBoundingRects(); transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight, mTmpMatrix); - bounds.transform(mTmpMatrix); - return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(bounds), + final Region region = Region.obtain(); + for (int i = 0; i < bounds.size(); i++) { + final Rect rect = bounds.get(i); + final RectF rectF = new RectF(bounds.get(i)); + mTmpMatrix.mapRect(rectF); + rectF.round(rect); + region.op(rect, Op.UNION); + } + + return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(region), rotated ? mInitialDisplayHeight : mInitialDisplayWidth, rotated ? mInitialDisplayWidth : mInitialDisplayHeight); } @@ -3538,7 +3549,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 +3712,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 +3740,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..f25ec5cd935e --- /dev/null +++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java @@ -0,0 +1,97 @@ +/* + * 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; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 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]; + private final int mOldRotation; + private final int mNewRotation; + + public ForcedSeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) { + mOldRotation = oldRotation; + mNewRotation = newRotation; + + 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()); + } + + public void dump(PrintWriter pw) { + pw.print("{old="); pw.print(mOldRotation); pw.print(", new="); pw.print(mNewRotation); + pw.print("}"); + } + + @Override + public String toString() { + StringWriter sw = new StringWriter(); + dump(new PrintWriter(sw)); + return "ForcedSeamlessRotator" + sw.toString(); + } +} diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 281e0a8441e2..a626663c2e67 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -40,6 +40,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; @@ -620,6 +621,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private void updateInputWindows(boolean inDrag) { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows"); + // TODO: multi-display navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY); pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY); @@ -645,6 +648,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle); clearInputWindowHandlesLw(); + + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @Override 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..e707636a11b9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1883,6 +1883,13 @@ public class WindowManagerService extends IWindowManager.Stub } win.setFrameNumber(frameNumber); + + if (win.mPendingForcedSeamlessRotate != null && !mWaitingForConfig) { + win.mPendingForcedSeamlessRotate.finish(win.mToken, win); + win.mFinishForcedSeamlessRotateFrameNumber = win.getFrameNumber(); + 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..009f3930d02e 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -125,6 +125,7 @@ import static com.android.server.wm.WindowStateProto.DECOR_FRAME; import static com.android.server.wm.WindowStateProto.DESTROYING; import static com.android.server.wm.WindowStateProto.DISPLAY_FRAME; import static com.android.server.wm.WindowStateProto.DISPLAY_ID; +import static com.android.server.wm.WindowStateProto.FINISHED_FORCED_SEAMLESS_ROTATION_FRAME; import static com.android.server.wm.WindowStateProto.FRAME; import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS; import static com.android.server.wm.WindowStateProto.HAS_SURFACE; @@ -137,6 +138,7 @@ import static com.android.server.wm.WindowStateProto.OUTSET_FRAME; import static com.android.server.wm.WindowStateProto.OVERSCAN_FRAME; import static com.android.server.wm.WindowStateProto.OVERSCAN_INSETS; import static com.android.server.wm.WindowStateProto.PARENT_FRAME; +import static com.android.server.wm.WindowStateProto.PENDING_FORCED_SEAMLESS_ROTATION; import static com.android.server.wm.WindowStateProto.REMOVED; import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT; import static com.android.server.wm.WindowStateProto.REQUESTED_HEIGHT; @@ -150,6 +152,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 +282,14 @@ 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; + long mFinishForcedSeamlessRotateFrameNumber; private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks; @@ -667,6 +679,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 +733,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 +1832,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); } @@ -3286,6 +3308,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP proto.write(REMOVED, mRemoved); proto.write(IS_ON_SCREEN, isOnScreen()); proto.write(IS_VISIBLE, isVisible()); + if (mForceSeamlesslyRotate) { + proto.write(PENDING_FORCED_SEAMLESS_ROTATION, mPendingForcedSeamlessRotate != null); + proto.write(FINISHED_FORCED_SEAMLESS_ROTATION_FRAME, + mFinishForcedSeamlessRotateFrameNumber); + } proto.end(token); } @@ -3462,6 +3489,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP pw.print(prefix); pw.print("mLastFreezeDuration="); TimeUtils.formatDuration(mLastFreezeDuration, pw); pw.println(); } + if (mForceSeamlesslyRotate) { + pw.print(prefix); pw.print("forceSeamlesslyRotate: pending="); + if (mPendingForcedSeamlessRotate != null) { + mPendingForcedSeamlessRotate.dump(pw); + } else { + pw.print("null"); + } + pw.print(" finishedFrameNumber="); pw.print(mFinishForcedSeamlessRotateFrameNumber); + pw.println(); + } if (mHScale != 1 || mVScale != 1) { pw.print(prefix); pw.print("mHScale="); pw.print(mHScale); pw.print(" mVScale="); pw.println(mVScale); @@ -4697,7 +4734,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 +4890,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/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java index 2c47a9432eff..1d378020fa4f 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java +++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java @@ -37,6 +37,7 @@ import android.graphics.Matrix; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.RectF; import android.os.IBinder; import android.os.UserHandle; import android.support.test.InstrumentationRegistry; @@ -172,15 +173,14 @@ public class PhoneWindowManagerTestBase { } private static DisplayCutout displayCutoutForRotation(int rotation) { - Path p = new Path(); - p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT, - Path.Direction.CCW); + RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT); Matrix m = new Matrix(); transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m); - p.transform(m); + m.mapRect(rectF); - return DisplayCutout.fromBounds(p); + return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top, + (int) rectF.right, (int) rectF.bottom); } static class TestContextWrapper extends ContextWrapper { 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/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 78099996a1a0..bdba3d5cd677 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -19,7 +19,9 @@ import static android.app.Notification.GROUP_ALERT_ALL; import static android.app.Notification.GROUP_ALERT_CHILDREN; import static android.app.Notification.GROUP_ALERT_SUMMARY; import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; @@ -149,6 +151,9 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN); mService.setUsageStats(mUsageStats); mService.setAccessibilityManager(accessibilityManager); + mService.mScreenOn = false; + mService.mInCall = false; + mService.mNotificationPulseEnabled = true; } // @@ -216,8 +221,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } private NotificationRecord getLightsNotification() { + return getNotificationRecord(mId, false /* insistent */, false /* once */, + false /* noisy */, false /* buzzy*/, true /* lights */); + } + + private NotificationRecord getLightsOnceNotification() { return getNotificationRecord(mId, false /* insistent */, true /* once */, - false /* noisy */, true /* buzzy*/, true /* lights */); + false /* noisy */, false /* buzzy*/, true /* lights */); } private NotificationRecord getCustomLightsNotification() { @@ -244,6 +254,12 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { groupKey, groupAlertBehavior, false); } + private NotificationRecord getLightsNotificationRecord(String groupKey, + int groupAlertBehavior) { + return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true, true, + true, groupKey, groupAlertBehavior, false); + } + private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once, boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration, boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior, @@ -369,6 +385,10 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mVibrator, never()).cancel(); } + private void verifyNeverLights() { + verify(mLight, never()).setFlashing(anyInt(), anyInt(), anyInt(), anyInt()); + } + private void verifyLights() { verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt()); } @@ -712,7 +732,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(summary); verifyBeepLooped(); - assertTrue(summary.isInterruptive()); + // summaries are never interruptive for notification counts + assertFalse(summary.isInterruptive()); } @Test @@ -990,6 +1011,156 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt()); } + @Test + public void testLightsScreenOn() { + mService.mScreenOn = true; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsInCall() { + mService.mInCall = true; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsSilentUpdate() { + NotificationRecord r = getLightsOnceNotification(); + mService.buzzBeepBlinkLocked(r); + verifyLights(); + assertTrue(r.isInterruptive()); + + r = getLightsOnceNotification(); + r.isUpdate = true; + mService.buzzBeepBlinkLocked(r); + // checks that lights happened once, i.e. this new call didn't trigger them again + verifyLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsUnimportant() { + NotificationRecord r = getLightsNotification(); + r.setImportance(IMPORTANCE_LOW, "testing"); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsNoLights() { + NotificationRecord r = getQuietNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsNoLightOnDevice() { + mService.mHasLight = false; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsLightsOffGlobally() { + mService.mNotificationPulseEnabled = false; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsDndIntercepted() { + NotificationRecord r = getLightsNotification(); + r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testGroupAlertSummaryNoLightsChild() { + NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY); + + mService.buzzBeepBlinkLocked(child); + + verifyNeverLights(); + assertFalse(child.isInterruptive()); + } + + @Test + public void testGroupAlertSummaryLightsSummary() { + NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY); + summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; + + mService.buzzBeepBlinkLocked(summary); + + verifyLights(); + // summaries should never count for interruptiveness counts + assertFalse(summary.isInterruptive()); + } + + @Test + public void testGroupAlertSummaryLightsNonGroupChild() { + NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_SUMMARY); + + mService.buzzBeepBlinkLocked(nonGroup); + + verifyLights(); + assertTrue(nonGroup.isInterruptive()); + } + + @Test + public void testGroupAlertChildNoLightsSummary() { + NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN); + summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; + + mService.buzzBeepBlinkLocked(summary); + + verifyNeverLights(); + assertFalse(summary.isInterruptive()); + } + + @Test + public void testGroupAlertChildLightsChild() { + NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN); + + mService.buzzBeepBlinkLocked(child); + + verifyLights(); + assertTrue(child.isInterruptive()); + } + + @Test + public void testGroupAlertChildLightsNonGroupSummary() { + NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_CHILDREN); + + mService.buzzBeepBlinkLocked(nonGroup); + + verifyLights(); + assertTrue(nonGroup.isInterruptive()); + } + + @Test + public void testGroupAlertAllLightsGroup() { + NotificationRecord group = getLightsNotificationRecord("a", GROUP_ALERT_ALL); + + mService.buzzBeepBlinkLocked(group); + + verifyLights(); + assertTrue(group.isInterruptive()); + } + static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> { private final int mRepeatIndex; 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/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java index 3c4e333b6be9..82e0fbe0e400 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java @@ -1,16 +1,16 @@ package com.android.server.slice; +import static android.testing.TestableContentResolver.UNSTABLE; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -71,11 +71,12 @@ public class PinnedSliceStateTest extends UiServiceTestCase { mSliceService = mock(SliceManagerService.class); when(mSliceService.getContext()).thenReturn(mContext); when(mSliceService.getLock()).thenReturn(new Object()); - when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper())); + when(mSliceService.getHandler()).thenReturn( + new Handler(TestableLooper.get(this).getLooper())); mContentProvider = mock(ContentProvider.class); mIContentProvider = mock(IContentProvider.class); when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider); - mContext.getContentResolver().addProvider(AUTH, mContentProvider); + mContext.getContentResolver().addProvider(AUTH, mContentProvider, UNSTABLE); mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg"); } diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 3bf951d4d8ca..468c8fa9e30c 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -45,6 +45,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.nio.channels.Channels; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -853,6 +854,8 @@ public abstract class Connection extends Conferenceable { private final OutputStreamWriter mPipeToInCall; private final ParcelFileDescriptor mFdFromInCall; private final ParcelFileDescriptor mFdToInCall; + + private final FileInputStream mFromInCallFileInputStream; private char[] mReadBuffer = new char[READ_BUFFER_SIZE]; /** @@ -861,8 +864,11 @@ public abstract class Connection extends Conferenceable { public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) { mFdFromInCall = fromInCall; mFdToInCall = toInCall; + mFromInCallFileInputStream = new FileInputStream(fromInCall.getFileDescriptor()); + + // Wrap the FileInputStream in a Channel so that it's interruptible. mPipeFromInCall = new InputStreamReader( - new FileInputStream(fromInCall.getFileDescriptor())); + Channels.newInputStream(Channels.newChannel(mFromInCallFileInputStream))); mPipeToInCall = new OutputStreamWriter( new FileOutputStream(toInCall.getFileDescriptor())); } @@ -910,7 +916,7 @@ public abstract class Connection extends Conferenceable { * not entered any new text yet. */ public String readImmediately() throws IOException { - if (mPipeFromInCall.ready()) { + if (mFromInCallFileInputStream.available() > 0) { return read(); } else { return null; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index a1f814bec37b..88cb6c938064 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -77,6 +77,30 @@ public class CarrierConfigManager { public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; + /** + * Boolean indicating if the "Call forwarding" item is visible in the Call Settings menu. + * true means visible. false means gone. + * @hide + */ + public static final String KEY_CALL_FORWARDING_VISIBILITY_BOOL = + "call_forwarding_visibility_bool"; + + /** + * Boolean indicating if the "Caller ID" item is visible in the Additional Settings menu. + * true means visible. false means gone. + * @hide + */ + public static final String KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL = + "additional_settings_caller_id_visibility_bool"; + + /** + * Boolean indicating if the "Call Waiting" item is visible in the Additional Settings menu. + * true means visible. false means gone. + * @hide + */ + public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL = + "additional_settings_call_waiting_visibility_bool"; + /** * Boolean indicating if the "Call barring" item is visible in the Call Settings menu. * true means visible. false means gone. @@ -2043,6 +2067,9 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false); sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false); + sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true); + sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true); + sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false); sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false); sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 5961e9aee01e..5bd4d22c6d5c 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)}. @@ -5518,23 +5534,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 9388ed155390..5dc0cff66910 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; @@ -633,33 +634,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 */ @@ -691,56 +692,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); } /** @@ -930,16 +931,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)); @@ -1021,31 +1022,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); } /** @@ -1068,29 +1069,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); } /** @@ -1102,22 +1103,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. @@ -1341,13 +1342,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/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java index bcad554b579f..a1bea4d417f9 100644 --- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java @@ -21,7 +21,6 @@ import android.content.ContentResolver; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.os.RemoteException; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -145,6 +144,18 @@ public final class CarrierAppUtils { telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + // add hiddenUntilInstalled flag for carrier apps and associated apps + packageManager.setSystemAppHiddenUntilInstalled(packageName, true); + List<ApplicationInfo> associatedAppList = associatedApps.get(packageName); + if (associatedAppList != null) { + for (ApplicationInfo associatedApp : associatedAppList) { + packageManager.setSystemAppHiddenUntilInstalled( + associatedApp.packageName, + true + ); + } + } + if (hasPrivileges) { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. @@ -152,9 +163,14 @@ public final class CarrierAppUtils { && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) { Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId); + packageManager.setSystemAppInstallState( + packageName, + true /*installed*/, + userId); packageManager.setApplicationEnabledSetting( packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, @@ -164,15 +180,20 @@ public final class CarrierAppUtils { } // Also enable any associated apps for this carrier app. - List<ApplicationInfo> associatedAppList = associatedApps.get(packageName); if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { if (associatedApp.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || associatedApp.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + || (associatedApp.flags + & ApplicationInfo.FLAG_INSTALLED) == 0) { Slog.i(TAG, "Update associated state(" + associatedApp.packageName + "): ENABLED for user " + userId); + packageManager.setSystemAppInstallState( + associatedApp.packageName, + true /*installed*/, + userId); packageManager.setApplicationEnabledSetting( associatedApp.packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, @@ -190,36 +211,33 @@ public final class CarrierAppUtils { // updated we shouldn't touch it. if (!ai.isUpdatedSystemApp() && ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { Slog.i(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED for user " + userId); - packageManager.setApplicationEnabledSetting( + packageManager.setSystemAppInstallState( packageName, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, - 0, - userId, - callingPackage); + false /*installed*/, + userId); } // Also disable any associated apps for this carrier app if this is the first // run. We avoid doing this a second time because it is brittle to rely on the // distinction between "default" and "enabled". if (!hasRunOnce) { - List<ApplicationInfo> associatedAppList = associatedApps.get(packageName); if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { if (associatedApp.enabledSetting - == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + && (associatedApp.flags + & ApplicationInfo.FLAG_INSTALLED) != 0) { Slog.i(TAG, "Update associated state(" + associatedApp.packageName + "): DISABLED_UNTIL_USED for user " + userId); - packageManager.setApplicationEnabledSetting( + packageManager.setSystemAppInstallState( associatedApp.packageName, - PackageManager - .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, - 0, - userId, - callingPackage); + false /*installed*/, + userId); } } } @@ -357,7 +375,8 @@ public final class CarrierAppUtils { String packageName) { try { ApplicationInfo ai = packageManager.getApplicationInfo(packageName, - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId); + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId); if (ai != null && ai.isSystemApp()) { return ai; } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index b519ebc8ba68..5ecdfc9e1d32 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/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java index 0850916ccbe5..a0afef8fcda3 100644 --- a/tests/testables/src/android/testing/TestableContentResolver.java +++ b/tests/testables/src/android/testing/TestableContentResolver.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.IContentProvider; import android.database.ContentObserver; import android.net.Uri; +import android.util.ArrayMap; import android.util.ArraySet; import com.google.android.collect.Maps; @@ -35,7 +36,11 @@ import java.util.Map; */ public class TestableContentResolver extends ContentResolver { - private final Map<String, ContentProvider> mProviders = Maps.newHashMap(); + public static final int STABLE = 1; + public static final int UNSTABLE = 2; + + private final Map<String, ContentProvider> mProviders = new ArrayMap<>(); + private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>(); private final ContentResolver mParent; private final ArraySet<ContentProvider> mInUse = new ArraySet<>(); private boolean mFallbackToExisting; @@ -62,7 +67,23 @@ public class TestableContentResolver extends ContentResolver { * subclasses, or null. */ public void addProvider(String name, ContentProvider provider) { - mProviders.put(name, provider); + addProvider(name, provider, STABLE | UNSTABLE); + } + + /** + * Adds access to a provider based on its authority + * + * @param name The authority name associated with the provider. + * @param provider An instance of {@link android.content.ContentProvider} or one of its + * subclasses, or null. + */ + public void addProvider(String name, ContentProvider provider, int flags) { + if ((flags & STABLE) != 0) { + mProviders.put(name, provider); + } + if ((flags & UNSTABLE) != 0) { + mUnstableProviders.put(name, provider); + } } @Override @@ -98,7 +119,7 @@ public class TestableContentResolver extends ContentResolver { @Override protected IContentProvider acquireUnstableProvider(Context c, String name) { - final ContentProvider provider = mProviders.get(name); + final ContentProvider provider = mUnstableProviders.get(name); if (provider != null) { return provider.getIContentProvider(); } else { @@ -128,7 +149,8 @@ public class TestableContentResolver extends ContentResolver { @Override public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { if (!mFallbackToExisting) return; - if (!mProviders.containsKey(uri.getAuthority())) { + if (!mProviders.containsKey(uri.getAuthority()) + && !mUnstableProviders.containsKey(uri.getAuthority())) { super.notifyChange(uri, observer, syncToNetwork); } } diff --git a/tests/testables/tests/src/android/testing/TestableContentResolverTest.java b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java new file mode 100644 index 000000000000..71afda0748c4 --- /dev/null +++ b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java @@ -0,0 +1,61 @@ +package android.testing; + +import android.content.ContentProvider; +import android.content.IContentProvider; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class TestableContentResolverTest { + + @Rule + public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext()); + private TestableContentResolver mContentResolver; + + @Before + public void setup() { + mContentResolver = new TestableContentResolver(mContext); + mContentResolver.setFallbackToExisting(false); + } + + @Test + public void testDefaultContentProvider() { + ContentProvider provider = Mockito.mock(ContentProvider.class); + IContentProvider iprovider = Mockito.mock(IContentProvider.class); + Mockito.when(provider.getIContentProvider()).thenReturn(iprovider); + mContentResolver.addProvider("test", provider); + + Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test")); + Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test")); + } + + @Test + public void testStableContentProvider() { + ContentProvider provider = Mockito.mock(ContentProvider.class); + IContentProvider iprovider = Mockito.mock(IContentProvider.class); + Mockito.when(provider.getIContentProvider()).thenReturn(iprovider); + mContentResolver.addProvider("test", provider, TestableContentResolver.STABLE); + + Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test")); + Assert.assertNull(mContentResolver.acquireUnstableProvider(mContext, "test")); + } + + @Test + public void testUnstableContentProvider() { + ContentProvider provider = Mockito.mock(ContentProvider.class); + IContentProvider iprovider = Mockito.mock(IContentProvider.class); + Mockito.when(provider.getIContentProvider()).thenReturn(iprovider); + mContentResolver.addProvider("test", provider, TestableContentResolver.UNSTABLE); + + Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test")); + Assert.assertNull(mContentResolver.acquireProvider(mContext, "test")); + } +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 66ccc6cdfbfb..af44b7e6cd16 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -147,6 +147,8 @@ interface IWifiManager boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName); + void notifyUserOfApBandConversion(String packageName); + Messenger getWifiServiceMessenger(String packageName); void enableTdls(String remoteIPAddress, boolean enable); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 25f35d0523a2..6963ed00b615 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2170,6 +2170,21 @@ public class WifiManager { } /** + * Method that triggers a notification to the user about a conversion to their saved AP config. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void notifyUserOfApBandConversion() { + Log.d(TAG, "apBand was converted, notify the user"); + try { + mService.notifyUserOfApBandConversion(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Enable/Disable TDLS on a specific local route. * * <p> |