diff options
68 files changed, 1762 insertions, 1079 deletions
diff --git a/api/current.txt b/api/current.txt index a52c1cc1cd41..21bab7cf5d1e 100755 --- a/api/current.txt +++ b/api/current.txt @@ -5676,6 +5676,7 @@ package android.app { method public java.lang.CharSequence getName(); method public android.net.Uri getSound(); method public long[] getVibrationPattern(); + method public boolean hasUserSetImportance(); method public void setBypassDnd(boolean); method public void setDescription(java.lang.String); method public void setGroup(java.lang.String); @@ -9168,6 +9169,7 @@ package android.content { method public int bulkInsert(android.net.Uri, android.content.ContentValues[]); method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle); method public android.net.Uri canonicalize(android.net.Uri); + method public final android.content.ContentProvider.CallingIdentity clearCallingIdentity(); method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public final java.lang.String getCallingPackage(); @@ -9195,6 +9197,7 @@ package android.content { method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); method public android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal); method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); + method public final void restoreCallingIdentity(android.content.ContentProvider.CallingIdentity); method protected final void setPathPermissions(android.content.pm.PathPermission[]); method protected final void setReadPermission(java.lang.String); method protected final void setWritePermission(java.lang.String); @@ -9203,6 +9206,9 @@ package android.content { method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); } + public final class ContentProvider.CallingIdentity { + } + public static abstract interface ContentProvider.PipeDataWriter<T> { method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T); } @@ -15311,20 +15317,9 @@ package android.graphics.fonts { method public java.nio.ByteBuffer getBuffer(); method public java.io.File getFile(); method public android.os.LocaleList getLocaleList(); + method public int getSlant(); method public int getTtcIndex(); method public int getWeight(); - method public boolean isItalic(); - field public static final int FONT_WEIGHT_BLACK = 900; // 0x384 - field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc - field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320 - field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8 - field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c - field public static final int FONT_WEIGHT_MAX = 1000; // 0x3e8 - field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4 - field public static final int FONT_WEIGHT_MIN = 1; // 0x1 - field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190 - field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258 - field public static final int FONT_WEIGHT_THIN = 100; // 0x64 } public static class Font.Builder { @@ -15337,7 +15332,7 @@ package android.graphics.fonts { method public android.graphics.fonts.Font build() throws java.io.IOException; method public android.graphics.fonts.Font.Builder setFontVariationSettings(java.lang.String); method public android.graphics.fonts.Font.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); - method public android.graphics.fonts.Font.Builder setItalic(boolean); + method public android.graphics.fonts.Font.Builder setSlant(int); method public android.graphics.fonts.Font.Builder setTtcIndex(int); method public android.graphics.fonts.Font.Builder setWeight(int); } @@ -15353,6 +15348,26 @@ package android.graphics.fonts { method public android.graphics.fonts.FontFamily build(); } + public final class FontStyle { + ctor public FontStyle(); + ctor public FontStyle(int, int); + method public int getSlant(); + method public int getWeight(); + field public static final int FONT_SLANT_ITALIC = 1; // 0x1 + field public static final int FONT_SLANT_UPRIGHT = 0; // 0x0 + field public static final int FONT_WEIGHT_BLACK = 900; // 0x384 + field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc + field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320 + field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8 + field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c + field public static final int FONT_WEIGHT_MAX = 1000; // 0x3e8 + field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4 + field public static final int FONT_WEIGHT_MIN = 1; // 0x1 + field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190 + field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258 + field public static final int FONT_WEIGHT_THIN = 100; // 0x64 + } + public final class FontVariationAxis { ctor public FontVariationAxis(java.lang.String, float); method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String); diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk index db864aed6bdc..eba558653b04 100644 --- a/cmds/incidentd/Android.mk +++ b/cmds/incidentd/Android.mk @@ -33,6 +33,9 @@ LOCAL_SRC_FILES := $(call all-cpp-files-under, src) \ LOCAL_CFLAGS += \ -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter +# Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed. +LOCAL_CFLAGS += -Wno-error=implicit-fallthrough + ifeq (debug,) LOCAL_CFLAGS += \ -g -O0 @@ -100,6 +103,9 @@ LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -Werror -Wall -Wno-unused-variable -Wunused-parameter +# Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed. +LOCAL_CFLAGS += -Wno-error=implicit-fallthrough + LOCAL_C_INCLUDES += $(LOCAL_PATH)/src LOCAL_SRC_FILES := $(call all-cpp-files-under, tests) \ diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 10ad1208d20d..c2fed66eea41 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -143,6 +143,7 @@ message Atom { BatteryCausedShutdown battery_caused_shutdown = 93; PhoneServiceStateChanged phone_service_state_changed = 94; PhoneStateChanged phone_state_changed = 95; + UserRestrictionChanged user_restriction_changed = 96; } // Pulled events will start at field 10000. @@ -183,7 +184,6 @@ message Atom { DiskIo disk_io = 10032; PowerProfile power_profile = 10033; ProcStats proc_stats_pkg_proc = 10034; - ProcessCpuTime process_cpu_time = 10035; NativeProcessMemoryState native_process_memory_state = 10036; } @@ -3035,17 +3035,15 @@ message PowerProfile { } /** - * Pulls process user time and system time. Puller takes a snapshot of all pids - * in the system and returns cpu stats for those that are working at the time. - * Dead pids will be dropped. Kernel processes are excluded. - * Min cool-down is 5 sec. + * Logs when a user restriction was added or removed. + * + * Logged from: + * frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java */ -message ProcessCpuTime { - optional int32 uid = 1 [(is_uid) = true]; - - optional string process_name = 2; - // Process cpu time in user space, cumulative from boot/process start - optional int64 user_time_millis = 3; - // Process cpu time in system space, cumulative from boot/process start - optional int64 system_time_millis = 4; -} +message UserRestrictionChanged { + // The raw string of the user restriction as defined in UserManager. + // Allowed values are defined in UserRestrictionsUtils#USER_RESTRICTIONS. + optional string restriction = 1; + // Whether the restriction is enabled or disabled. + optional bool enabled = 2; +}
\ No newline at end of file diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 8871d4d054c5..1a9ba8a8de17 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -229,9 +229,6 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // PowerProfile constants for power model calculations. {android::util::POWER_PROFILE, {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, - // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses. - {android::util::PROCESS_CPU_TIME, - {{}, {}, 5 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 857c39045085..bbc3f35aa05a 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1383,62 +1383,6 @@ Landroid/service/wallpaper/IWallpaperEngine;->dispatchWallpaperCommand(Ljava/lan Landroid/service/wallpaper/IWallpaperEngine;->setVisibility(Z)V Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/wallpaper/IWallpaperService; Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V -Landroid/system/Int32Ref;->value:I -Landroid/system/OsConstants;-><init>()V -Landroid/system/OsConstants;->AF_NETLINK:I -Landroid/system/OsConstants;->AF_PACKET:I -Landroid/system/OsConstants;->ARPHRD_ETHER:I -Landroid/system/OsConstants;->ARPHRD_LOOPBACK:I -Landroid/system/OsConstants;->CAP_TO_INDEX(I)I -Landroid/system/OsConstants;->CAP_TO_MASK(I)I -Landroid/system/OsConstants;->ENONET:I -Landroid/system/OsConstants;->ETH_P_ALL:I -Landroid/system/OsConstants;->ETH_P_ARP:I -Landroid/system/OsConstants;->ETH_P_IP:I -Landroid/system/OsConstants;->ETH_P_IPV6:I -Landroid/system/OsConstants;->EUSERS:I -Landroid/system/OsConstants;->ICMP6_ECHO_REPLY:I -Landroid/system/OsConstants;->ICMP6_ECHO_REQUEST:I -Landroid/system/OsConstants;->ICMP_ECHO:I -Landroid/system/OsConstants;->ICMP_ECHOREPLY:I -Landroid/system/OsConstants;->initConstants()V -Landroid/system/OsConstants;->IP_MULTICAST_ALL:I -Landroid/system/OsConstants;->IP_RECVTOS:I -Landroid/system/OsConstants;->MAP_POPULATE:I -Landroid/system/OsConstants;->NETLINK_NETFILTER:I -Landroid/system/OsConstants;->NETLINK_ROUTE:I -Landroid/system/OsConstants;->O_DIRECT:I -Landroid/system/OsConstants;->placeholder()I -Landroid/system/OsConstants;->PR_CAP_AMBIENT:I -Landroid/system/OsConstants;->PR_CAP_AMBIENT_RAISE:I -Landroid/system/OsConstants;->RLIMIT_NOFILE:I -Landroid/system/OsConstants;->RTMGRP_IPV4_IFADDR:I -Landroid/system/OsConstants;->RTMGRP_IPV4_MROUTE:I -Landroid/system/OsConstants;->RTMGRP_IPV4_ROUTE:I -Landroid/system/OsConstants;->RTMGRP_IPV4_RULE:I -Landroid/system/OsConstants;->RTMGRP_IPV6_IFADDR:I -Landroid/system/OsConstants;->RTMGRP_IPV6_IFINFO:I -Landroid/system/OsConstants;->RTMGRP_IPV6_MROUTE:I -Landroid/system/OsConstants;->RTMGRP_IPV6_PREFIX:I -Landroid/system/OsConstants;->RTMGRP_IPV6_ROUTE:I -Landroid/system/OsConstants;->RTMGRP_LINK:I -Landroid/system/OsConstants;->RTMGRP_NEIGH:I -Landroid/system/OsConstants;->RTMGRP_NOTIFY:I -Landroid/system/OsConstants;->RTMGRP_TC:I -Landroid/system/OsConstants;->SO_DOMAIN:I -Landroid/system/OsConstants;->SO_PROTOCOL:I -Landroid/system/OsConstants;->SPLICE_F_MORE:I -Landroid/system/OsConstants;->SPLICE_F_MOVE:I -Landroid/system/OsConstants;->SPLICE_F_NONBLOCK:I -Landroid/system/OsConstants;->TIOCOUTQ:I -Landroid/system/OsConstants;->UDP_ENCAP:I -Landroid/system/OsConstants;->UDP_ENCAP_ESPINUDP:I -Landroid/system/OsConstants;->UDP_ENCAP_ESPINUDP_NON_IKE:I -Landroid/system/OsConstants;->UNIX_PATH_MAX:I -Landroid/system/OsConstants;->XATTR_CREATE:I -Landroid/system/OsConstants;->XATTR_REPLACE:I -Landroid/system/OsConstants;->_LINUX_CAPABILITY_VERSION_3:I -Landroid/system/StructTimeval;->fromMillis(J)Landroid/system/StructTimeval; Landroid/telephony/CarrierMessagingServiceManager;-><init>()V Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants; Landroid/util/Singleton;-><init>()V @@ -2339,93 +2283,6 @@ Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/andr Lcom/google/android/mms/util/PduCache;->purgeAll()V Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu; Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri; -Ldalvik/system/BaseDexClassLoader;-><init>(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;Ljava/lang/ClassLoader;Z)V -Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V -Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;Z)V -Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String; -Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList; -Ldalvik/system/BlockGuard$BlockGuardPolicyException;-><init>(IILjava/lang/String;)V -Ldalvik/system/BlockGuard$BlockGuardPolicyException;->mMessage:Ljava/lang/String; -Ldalvik/system/BlockGuard$BlockGuardPolicyException;->mPolicyState:I -Ldalvik/system/BlockGuard$BlockGuardPolicyException;->mPolicyViolated:I -Ldalvik/system/BlockGuard$Policy;->onNetwork()V -Ldalvik/system/BlockGuard$Policy;->onReadFromDisk()V -Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy; -Ldalvik/system/BlockGuard;->LAX_POLICY:Ldalvik/system/BlockGuard$Policy; -Ldalvik/system/BlockGuard;->setThreadPolicy(Ldalvik/system/BlockGuard$Policy;)V -Ldalvik/system/BlockGuard;->threadPolicy:Ljava/lang/ThreadLocal; -Ldalvik/system/CloseGuard$DefaultReporter;-><init>()V -Ldalvik/system/CloseGuard$Reporter;->report(Ljava/lang/String;Ljava/lang/Throwable;)V -Ldalvik/system/CloseGuard;-><init>()V -Ldalvik/system/CloseGuard;->close()V -Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard; -Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V -Ldalvik/system/CloseGuard;->setEnabled(Z)V -Ldalvik/system/CloseGuard;->setReporter(Ldalvik/system/CloseGuard$Reporter;)V -Ldalvik/system/CloseGuard;->warnIfOpen()V -Ldalvik/system/DexFile$DFEnum;->mNameList:[Ljava/lang/String; -Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String; -Ldalvik/system/DexFile;->isBackedByOatFile()Z -Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class; -Ldalvik/system/DexFile;->loadDex(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ldalvik/system/DexFile; -Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object; -Ldalvik/system/DexFile;->mFileName:Ljava/lang/String; -Ldalvik/system/DexFile;->mInternalCookie:Ljava/lang/Object; -Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object; -Ldalvik/system/DexFile;->openDexFileNative(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object; -Ldalvik/system/DexPathList$Element;-><init>(Ldalvik/system/DexFile;Ljava/io/File;)V -Ldalvik/system/DexPathList$Element;-><init>(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V -Ldalvik/system/DexPathList$Element;->dexFile:Ldalvik/system/DexFile; -Ldalvik/system/DexPathList$Element;->path:Ljava/io/File; -Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V -Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File; -Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V -Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V -Ldalvik/system/DexPathList;->addNativePath(Ljava/util/Collection;)V -Ldalvik/system/DexPathList;->definingContext:Ljava/lang/ClassLoader; -Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element; -Ldalvik/system/DexPathList;->dexElementsSuppressedExceptions:[Ljava/io/IOException; -Ldalvik/system/DexPathList;->loadDexFile(Ljava/io/File;Ljava/io/File;Ljava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ldalvik/system/DexFile; -Ldalvik/system/DexPathList;->makeDexElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;Ljava/lang/ClassLoader;)[Ldalvik/system/DexPathList$Element; -Ldalvik/system/DexPathList;->makeInMemoryDexElements([Ljava/nio/ByteBuffer;Ljava/util/List;)[Ldalvik/system/DexPathList$Element; -Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;)[Ldalvik/system/DexPathList$NativeLibraryElement; -Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element; -Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List; -Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement; -Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List; -Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List; -Ldalvik/system/SocketTagger;->get()Ldalvik/system/SocketTagger; -Ldalvik/system/SocketTagger;->tag(Ljava/net/Socket;)V -Ldalvik/system/SocketTagger;->untag(Ljava/net/Socket;)V -Ldalvik/system/VMDebug;->allowHiddenApiReflectionFrom(Ljava/lang/Class;)V -Ldalvik/system/VMDebug;->dumpReferenceTables()V -Ldalvik/system/VMDebug;->isDebuggerConnected()Z -Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J -Ldalvik/system/VMRuntime;->clearGrowthLimit()V -Ldalvik/system/VMRuntime;->gcSoftReferences()V -Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String; -Ldalvik/system/VMRuntime;->getExternalBytesAllocated()J -Ldalvik/system/VMRuntime;->getInstructionSet(Ljava/lang/String;)Ljava/lang/String; -Ldalvik/system/VMRuntime;->getMinimumHeapSize()J -Ldalvik/system/VMRuntime;->getRuntime()Ldalvik/system/VMRuntime; -Ldalvik/system/VMRuntime;->is64Bit()Z -Ldalvik/system/VMRuntime;->is64BitAbi(Ljava/lang/String;)Z -Ldalvik/system/VMRuntime;->newNonMovableArray(Ljava/lang/Class;I)Ljava/lang/Object; -Ldalvik/system/VMRuntime;->registerNativeAllocation(I)V -Ldalvik/system/VMRuntime;->registerNativeFree(I)V -Ldalvik/system/VMRuntime;->runFinalization(J)V -Ldalvik/system/VMRuntime;->runFinalizationSync()V -Ldalvik/system/VMRuntime;->setMinimumHeapSize(J)J -Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F -Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V -Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z -Ldalvik/system/VMRuntime;->trackExternalFree(J)V -Ldalvik/system/VMRuntime;->vmInstructionSet()Ljava/lang/String; -Ldalvik/system/VMRuntime;->vmLibrary()Ljava/lang/String; -Ldalvik/system/VMStack;->fillStackTraceElements(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I -Ldalvik/system/VMStack;->getCallingClassLoader()Ljava/lang/ClassLoader; -Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class; -Ldalvik/system/VMStack;->getThreadStackTrace(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement; Ljava/io/Console;->encoding()Ljava/lang/String; Ljava/io/File;->filePath:Ljava/nio/file/Path; Ljava/io/File;->fs:Ljava/io/FileSystem; @@ -2501,18 +2358,6 @@ Ljava/lang/Class;->name:Ljava/lang/String; Ljava/lang/Class;->objectSize:I Ljava/lang/Class;->status:I Ljava/lang/ClassLoader;->parent:Ljava/lang/ClassLoader; -Ljava/lang/Daemons$Daemon;->isRunning()Z -Ljava/lang/Daemons$Daemon;->start()V -Ljava/lang/Daemons$Daemon;->stop()V -Ljava/lang/Daemons$Daemon;->thread:Ljava/lang/Thread; -Ljava/lang/Daemons$FinalizerDaemon;->finalizingObject:Ljava/lang/Object; -Ljava/lang/Daemons$FinalizerDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerDaemon; -Ljava/lang/Daemons$FinalizerWatchdogDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon; -Ljava/lang/Daemons$ReferenceQueueDaemon;->INSTANCE:Ljava/lang/Daemons$ReferenceQueueDaemon; -Ljava/lang/Daemons;->MAX_FINALIZE_NANOS:J -Ljava/lang/Daemons;->requestHeapTrim()V -Ljava/lang/Daemons;->start()V -Ljava/lang/Daemons;->stop()V Ljava/lang/Double;->value:D Ljava/lang/Enum;->getSharedConstants(Ljava/lang/Class;)[Ljava/lang/Enum; Ljava/lang/Enum;->name:Ljava/lang/String; @@ -2522,11 +2367,6 @@ Ljava/lang/Integer;->value:I Ljava/lang/invoke/MethodHandles$Lookup;-><init>(Ljava/lang/Class;I)V Ljava/lang/Long;->value:J Ljava/lang/Object;->identityHashCode(Ljava/lang/Object;)I -Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V -Ljava/lang/ref/FinalizerReference;->head:Ljava/lang/ref/FinalizerReference; -Ljava/lang/ref/FinalizerReference;->next:Ljava/lang/ref/FinalizerReference; -Ljava/lang/ref/FinalizerReference;->queue:Ljava/lang/ref/ReferenceQueue; -Ljava/lang/ref/FinalizerReference;->remove(Ljava/lang/ref/FinalizerReference;)V Ljava/lang/ref/Reference;->getReferent()Ljava/lang/Object; Ljava/lang/ref/Reference;->referent:Ljava/lang/Object; Ljava/lang/ref/ReferenceQueue;->add(Ljava/lang/ref/Reference;)V @@ -2669,12 +2509,6 @@ Ljava/nio/CharBuffer;->toString(II)Ljava/lang/String; Ljava/nio/charset/Charset;->defaultCharset:Ljava/nio/charset/Charset; Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z Ljava/nio/DirectByteBuffer;-><init>(JI)V -Ljava/nio/NIOAccess;->getBaseArray(Ljava/nio/Buffer;)Ljava/lang/Object; -Ljava/nio/NIOAccess;->getBaseArrayOffset(Ljava/nio/Buffer;)I -Ljava/nio/NIOAccess;->getBasePointer(Ljava/nio/Buffer;)J -Ljava/nio/NioUtils;->freeDirectBuffer(Ljava/nio/ByteBuffer;)V -Ljava/nio/NioUtils;->unsafeArray(Ljava/nio/ByteBuffer;)[B -Ljava/nio/NioUtils;->unsafeArrayOffset(Ljava/nio/ByteBuffer;)I Ljava/security/KeyPairGenerator;->getInstance(Lsun/security/jca/GetInstance$Instance;Ljava/lang/String;)Ljava/security/KeyPairGenerator; Ljava/security/KeyStore;->keyStoreSpi:Ljava/security/KeyStoreSpi; Ljava/security/Signature;->getInstance(Lsun/security/jca/GetInstance$Instance;Ljava/lang/String;)Ljava/security/Signature; @@ -2790,9 +2624,6 @@ Ljava/util/zip/ZipOutputStream;->written:J Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory; Ljavax/net/ssl/SSLSocketFactory;->createSocket(Ljava/net/Socket;Ljava/io/InputStream;Z)Ljava/net/Socket; Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory; -Llibcore/icu/ICU;->addLikelySubtags(Ljava/util/Locale;)Ljava/util/Locale; -Llibcore/util/BasicLruCache;->map:Ljava/util/LinkedHashMap; -Llibcore/util/ZoneInfo;->mTransitions:[J Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String; Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl; @@ -2811,100 +2642,6 @@ Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap; Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String; Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType; Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String; -Lorg/json/JSONArray;->values:Ljava/util/List; -Lorg/json/JSONArray;->writeTo(Lorg/json/JSONStringer;)V -Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject; -Lorg/json/JSONObject;->checkName(Ljava/lang/String;)Ljava/lang/String; -Lorg/json/JSONObject;->keySet()Ljava/util/Set; -Lorg/json/JSONObject;->nameValuePairs:Ljava/util/LinkedHashMap; -Lorg/json/JSONObject;->NEGATIVE_ZERO:Ljava/lang/Double; -Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V -Lorg/json/JSONStringer;-><init>(I)V -Lorg/json/JSONStringer;->beforeKey()V -Lorg/json/JSONStringer;->beforeValue()V -Lorg/json/JSONStringer;->close(Lorg/json/JSONStringer$Scope;Lorg/json/JSONStringer$Scope;Ljava/lang/String;)Lorg/json/JSONStringer; -Lorg/json/JSONStringer;->indent:Ljava/lang/String; -Lorg/json/JSONStringer;->newline()V -Lorg/json/JSONStringer;->open(Lorg/json/JSONStringer$Scope;Ljava/lang/String;)Lorg/json/JSONStringer; -Lorg/json/JSONStringer;->out:Ljava/lang/StringBuilder; -Lorg/json/JSONStringer;->peek()Lorg/json/JSONStringer$Scope; -Lorg/json/JSONStringer;->replaceTop(Lorg/json/JSONStringer$Scope;)V -Lorg/json/JSONStringer;->stack:Ljava/util/List; -Lorg/json/JSONStringer;->string(Ljava/lang/String;)V -Lorg/json/JSONTokener;->in:Ljava/lang/String; -Lorg/json/JSONTokener;->nextCleanInternal()I -Lorg/json/JSONTokener;->nextToInternal(Ljava/lang/String;)Ljava/lang/String; -Lorg/json/JSONTokener;->pos:I -Lorg/json/JSONTokener;->readArray()Lorg/json/JSONArray; -Lorg/json/JSONTokener;->readEscapeCharacter()C -Lorg/json/JSONTokener;->readLiteral()Ljava/lang/Object; -Lorg/json/JSONTokener;->readObject()Lorg/json/JSONObject; -Lorg/json/JSONTokener;->skipToEndOfLine()V -Lorg/w3c/dom/ls/LSSerializerFilter;->getWhatToShow()I -Lorg/w3c/dom/traversal/NodeFilter;->acceptNode(Lorg/w3c/dom/Node;)S -Lorg/w3c/dom/traversal/NodeIterator;->detach()V -Lorg/w3c/dom/traversal/NodeIterator;->nextNode()Lorg/w3c/dom/Node; -Lorg/xml/sax/ext/Attributes2Impl;->declared:[Z -Lorg/xml/sax/ext/Attributes2Impl;->specified:[Z -Lorg/xml/sax/ext/Locator2Impl;->encoding:Ljava/lang/String; -Lorg/xml/sax/ext/Locator2Impl;->version:Ljava/lang/String; -Lorg/xml/sax/helpers/AttributesImpl;->badIndex(I)V -Lorg/xml/sax/helpers/AttributesImpl;->data:[Ljava/lang/String; -Lorg/xml/sax/helpers/AttributesImpl;->ensureCapacity(I)V -Lorg/xml/sax/helpers/AttributesImpl;->length:I -Lorg/xml/sax/helpers/LocatorImpl;->columnNumber:I -Lorg/xml/sax/helpers/LocatorImpl;->lineNumber:I -Lorg/xml/sax/helpers/LocatorImpl;->publicId:Ljava/lang/String; -Lorg/xml/sax/helpers/LocatorImpl;->systemId:Ljava/lang/String; -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 -Lorg/xml/sax/helpers/ParserAdapter;->contentHandler:Lorg/xml/sax/ContentHandler; -Lorg/xml/sax/helpers/ParserAdapter;->dtdHandler:Lorg/xml/sax/DTDHandler; -Lorg/xml/sax/helpers/ParserAdapter;->entityResolver:Lorg/xml/sax/EntityResolver; -Lorg/xml/sax/helpers/ParserAdapter;->errorHandler:Lorg/xml/sax/ErrorHandler; -Lorg/xml/sax/helpers/ParserAdapter;->locator:Lorg/xml/sax/Locator; -Lorg/xml/sax/helpers/ParserAdapter;->makeException(Ljava/lang/String;)Lorg/xml/sax/SAXParseException; -Lorg/xml/sax/helpers/ParserAdapter;->nameParts:[Ljava/lang/String; -Lorg/xml/sax/helpers/ParserAdapter;->namespaces:Z -Lorg/xml/sax/helpers/ParserAdapter;->nsSupport:Lorg/xml/sax/helpers/NamespaceSupport; -Lorg/xml/sax/helpers/ParserAdapter;->parser:Lorg/xml/sax/Parser; -Lorg/xml/sax/helpers/ParserAdapter;->parsing:Z -Lorg/xml/sax/helpers/ParserAdapter;->prefixes:Z -Lorg/xml/sax/helpers/ParserAdapter;->processName(Ljava/lang/String;ZZ)[Ljava/lang/String; -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; -Lorg/xml/sax/helpers/XMLFilterImpl;->errorHandler:Lorg/xml/sax/ErrorHandler; -Lorg/xml/sax/helpers/XMLFilterImpl;->locator:Lorg/xml/sax/Locator; -Lorg/xml/sax/helpers/XMLFilterImpl;->parent:Lorg/xml/sax/XMLReader; -Lorg/xml/sax/helpers/XMLFilterImpl;->setupParse()V -Lorg/xml/sax/helpers/XMLReaderAdapter;->documentHandler:Lorg/xml/sax/DocumentHandler; -Lorg/xml/sax/helpers/XMLReaderAdapter;->qAtts:Lorg/xml/sax/helpers/XMLReaderAdapter$AttributesAdapter; -Lorg/xml/sax/helpers/XMLReaderAdapter;->setup(Lorg/xml/sax/XMLReader;)V -Lorg/xml/sax/helpers/XMLReaderAdapter;->setupXMLReader()V -Lorg/xml/sax/helpers/XMLReaderAdapter;->xmlReader:Lorg/xml/sax/XMLReader; -Lorg/xml/sax/helpers/XMLReaderFactory;->loadClass(Ljava/lang/ClassLoader;Ljava/lang/String;)Lorg/xml/sax/XMLReader; -Lorg/xml/sax/InputSource;->byteStream:Ljava/io/InputStream; -Lorg/xml/sax/InputSource;->characterStream:Ljava/io/Reader; -Lorg/xml/sax/InputSource;->encoding:Ljava/lang/String; -Lorg/xml/sax/InputSource;->publicId:Ljava/lang/String; -Lorg/xml/sax/InputSource;->systemId:Ljava/lang/String; -Lorg/xml/sax/SAXException;->exception:Ljava/lang/Exception; -Lorg/xml/sax/SAXParseException;->columnNumber:I -Lorg/xml/sax/SAXParseException;->init(Ljava/lang/String;Ljava/lang/String;II)V -Lorg/xml/sax/SAXParseException;->lineNumber:I -Lorg/xml/sax/SAXParseException;->publicId:Ljava/lang/String; -Lorg/xml/sax/SAXParseException;->systemId:Ljava/lang/String; Lsun/misc/Cleaner;->clean()V Lsun/misc/Unsafe;->addressSize()I Lsun/misc/Unsafe;->allocateInstance(Ljava/lang/Class;)Ljava/lang/Object; diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 45e38cf95de0..e5e64d34f721 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -122,14 +122,6 @@ Landroid/os/UserHandle;->isSameApp(II)Z Landroid/os/UserManager;->hasUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z Landroid/os/UserManager;->isAdminUser()Z Landroid/R$styleable;->CheckBoxPreference:[I -Landroid/system/NetlinkSocketAddress;-><init>(II)V -Landroid/system/Os;->bind(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V -Landroid/system/Os;->connect(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V -Landroid/system/Os;->sendto(Ljava/io/FileDescriptor;[BIIILjava/net/SocketAddress;)I -Landroid/system/Os;->setsockoptIfreq(Ljava/io/FileDescriptor;IILjava/lang/String;)V -Landroid/system/Os;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V -Landroid/system/PacketSocketAddress;-><init>(I[B)V -Landroid/system/PacketSocketAddress;-><init>(SI)V Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V Landroid/telephony/ims/compat/ImsService;-><init>()V Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;-><init>()V diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java index ceb828b64add..0e428ae164a4 100644 --- a/core/java/android/app/FragmentTransition.java +++ b/core/java/android/app/FragmentTransition.java @@ -1013,6 +1013,11 @@ class FragmentTransition { replaceTargets(sharedElementTransition, sharedElementsIn, null); } } + + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + } }); } diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 848def63177e..9f93e1765da3 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -603,9 +603,10 @@ public final class NotificationChannel implements Parcelable { } /** - * @hide + * Returns whether the user has chosen the importance of this channel, either to affirm the + * initial selection from the app, or changed it to be higher or lower. */ - public boolean isImportanceLocked() { + public boolean hasUserSetImportance() { return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 2a03787f134c..145c92731458 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -822,6 +822,48 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } /** + * Opaque token representing the identity of an incoming IPC. + */ + public final class CallingIdentity { + /** {@hide} */ + public final long binderToken; + /** {@hide} */ + public final String callingPackage; + + /** {@hide} */ + public CallingIdentity(long binderToken, String callingPackage) { + this.binderToken = binderToken; + this.callingPackage = callingPackage; + } + } + + /** + * Reset the identity of the incoming IPC on the current thread. + * <p> + * Internally this calls {@link Binder#clearCallingIdentity()} and also + * clears any value stored in {@link #getCallingPackage()}. + * + * @return Returns an opaque token that can be used to restore the original + * calling identity by passing it to + * {@link #restoreCallingIdentity}. + */ + public final @NonNull CallingIdentity clearCallingIdentity() { + return new CallingIdentity(Binder.clearCallingIdentity(), setCallingPackage(null)); + } + + /** + * Restore the identity of the incoming IPC on the current thread back to a + * previously identity that was returned by {@link #clearCallingIdentity}. + * <p> + * Internally this calls {@link Binder#restoreCallingIdentity(long)} and + * also restores any value stored in {@link #getCallingPackage()}. + */ + public final void restoreCallingIdentity(@NonNull CallingIdentity identity) { + Binder.restoreCallingIdentity(identity.binderToken); + mCallingPackage.set(identity.callingPackage); + } + + /** * Change the authorities of the ContentProvider. * This is normally set for you from its manifest information when the provider is first * created. diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 0d5d54704c4f..00b989e03c61 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -272,6 +272,10 @@ public class UserManager { * * Specifies if all users on the device are disallowed from enabling the * "Unknown Sources" setting, that allows installation of apps from unknown sources. + * + * This restriction can be enabled by the profile owner, in which case all accounts and + * profiles will be affected. + * * The default value is <code>false</code>. * * <p>Key for user restrictions. diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 50ca4abd6713..df771df5de0d 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1538,6 +1538,9 @@ public class StorageManager { * @hide */ public File translateAppToSystem(File file, String packageName) { + // We can only translate absolute paths + if (!file.isAbsolute()) return file; + try { return new File(mStorageManager.translateAppToSystem(file.getAbsolutePath(), packageName, mContext.getUserId())); @@ -1553,6 +1556,9 @@ public class StorageManager { * @hide */ public File translateSystemToApp(File file, String packageName) { + // We can only translate absolute paths + if (!file.isAbsolute()) return file; + try { return new File(mStorageManager.translateSystemToApp(file.getAbsolutePath(), packageName, mContext.getUserId())); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index d7fe15d0e925..b8e03876a836 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -737,7 +737,8 @@ public abstract class NotificationListenerService extends Service { * <p>This method will throw a security exception if you don't have access to notifications * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated - * device} in order to use this method. + * device} or be the {@link NotificationAssistantService notification assistant} in order to + * use this method. * * @param pkg The package to retrieve channels for. */ @@ -760,7 +761,8 @@ public abstract class NotificationListenerService extends Service { * <p>This method will throw a security exception if you don't have access to notifications * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated - * device} in order to use this method. + * device} or be the {@link NotificationAssistantService notification assistant} in order to + * use this method. * * @param pkg The package to retrieve channel groups for. */ diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 0808cdd6aedb..3ab8a0a8885f 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1806,6 +1806,7 @@ public abstract class Layout { } } + /** * Fills in the specified Path with a representation of a cursor * at the specified offset. This will often be a vertical line @@ -1821,7 +1822,6 @@ public abstract class Layout { boolean clamped = shouldClampCursor(line); float h1 = getPrimaryHorizontal(point, clamped) - 0.5f; - float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point, clamped) - 0.5f : h1; int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) | TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING); @@ -1839,34 +1839,24 @@ public abstract class Layout { if (h1 < 0.5f) h1 = 0.5f; - if (h2 < 0.5f) - h2 = 0.5f; - if (Float.compare(h1, h2) == 0) { - dest.moveTo(h1, top); - dest.lineTo(h1, bottom); - } else { - dest.moveTo(h1, top); - dest.lineTo(h1, (top + bottom) >> 1); - - dest.moveTo(h2, (top + bottom) >> 1); - dest.lineTo(h2, bottom); - } + dest.moveTo(h1, top); + dest.lineTo(h1, bottom); if (caps == 2) { - dest.moveTo(h2, bottom); - dest.lineTo(h2 - dist, bottom + dist); - dest.lineTo(h2, bottom); - dest.lineTo(h2 + dist, bottom + dist); + dest.moveTo(h1, bottom); + dest.lineTo(h1 - dist, bottom + dist); + dest.lineTo(h1, bottom); + dest.lineTo(h1 + dist, bottom + dist); } else if (caps == 1) { - dest.moveTo(h2, bottom); - dest.lineTo(h2 - dist, bottom + dist); + dest.moveTo(h1, bottom); + dest.lineTo(h1 - dist, bottom + dist); - dest.moveTo(h2 - dist, bottom + dist - 0.5f); - dest.lineTo(h2 + dist, bottom + dist - 0.5f); + dest.moveTo(h1 - dist, bottom + dist - 0.5f); + dest.lineTo(h1 + dist, bottom + dist - 0.5f); - dest.moveTo(h2 + dist, bottom + dist); - dest.lineTo(h2, bottom); + dest.moveTo(h1 + dist, bottom + dist); + dest.lineTo(h1, bottom); } if (fn == 2) { diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index f846a356d8fa..23557694a48d 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -22,7 +22,7 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.LeakyTypefaceStorage; import android.graphics.Typeface; -import android.graphics.fonts.Font; +import android.graphics.fonts.FontStyle; import android.os.LocaleList; import android.os.Parcel; import android.text.ParcelableSpan; @@ -490,7 +490,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl if (styledTypeface != null) { final Typeface readyTypeface; if (mTextFontWeight >= 0) { - final int weight = Math.min(Font.FONT_WEIGHT_MAX, mTextFontWeight); + final int weight = Math.min(FontStyle.FONT_WEIGHT_MAX, mTextFontWeight); final boolean italic = (style & Typeface.ITALIC) != 0; readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic)); } else { diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index 4608e205ec7c..0e5252e21a64 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -315,6 +315,7 @@ public class TransitionManager { ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot); currentTransitions.remove(transition); + transition.removeListener(this); } }); mTransition.captureValues(mSceneRoot, false); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index a401c6def23a..e370e1175de5 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -59,7 +59,10 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.autofill.AutofillManager; import com.android.internal.annotations.GuardedBy; +import com.android.internal.inputmethod.InputMethodDebug; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; +import com.android.internal.inputmethod.StartInputReason; +import com.android.internal.inputmethod.UnbindReason; import com.android.internal.os.SomeArgs; import com.android.internal.view.IInputConnectionWrapper; import com.android.internal.view.IInputContext; @@ -67,7 +70,6 @@ import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; -import com.android.internal.view.InputMethodClient; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -540,17 +542,16 @@ public final class InputMethodManager { mCurId = res.id; mBindSequence = res.sequence; } - startInputInner(InputMethodClient.START_INPUT_REASON_BOUND_TO_IMMS, - null, 0, 0, 0); + startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0); return; } case MSG_UNBIND: { final int sequence = msg.arg1; - @InputMethodClient.UnbindReason + @UnbindReason final int reason = msg.arg2; if (DEBUG) { Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence + - " reason=" + InputMethodClient.getUnbindReason(reason)); + " reason=" + InputMethodDebug.unbindReasonToString(reason)); } final boolean startInput; synchronized (mH) { @@ -567,8 +568,7 @@ public final class InputMethodManager { } if (startInput) { startInputInner( - InputMethodClient.START_INPUT_REASON_UNBOUND_FROM_IMMS, null, 0, 0, - 0); + StartInputReason.UNBOUND_FROM_IMMS, null, 0, 0, 0); } return; } @@ -597,9 +597,8 @@ public final class InputMethodManager { // handling this message. if (mServedView != null && canStartInput(mServedView)) { if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) { - final int reason = active ? - InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS : - InputMethodClient.START_INPUT_REASON_DEACTIVATED_BY_IMMS; + final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS + : StartInputReason.DEACTIVATED_BY_IMMS; startInputInner(reason, null, 0, 0, 0); } } @@ -696,7 +695,7 @@ public final class InputMethodManager { } @Override - public void onUnbindMethod(int sequence, @InputMethodClient.UnbindReason int unbindReason) { + public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) { mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget(); } @@ -1386,11 +1385,10 @@ public final class InputMethodManager { mServedConnecting = true; } - startInputInner(InputMethodClient.START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, null, 0, - 0, 0); + startInputInner(StartInputReason.APP_CALLED_RESTART_INPUT_API, null, 0, 0, 0); } - boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason, + boolean startInputInner(@StartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, int controlFlags, int softInputMode, int windowFlags) { final View view; @@ -1400,7 +1398,7 @@ public final class InputMethodManager { // Make sure we have a window token for the served view. if (DEBUG) { Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) + - " reason=" + InputMethodClient.getStartInputReason(startInputReason)); + " reason=" + InputMethodDebug.startInputReasonToString(startInputReason)); } if (view == null) { if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); @@ -1519,7 +1517,7 @@ public final class InputMethodManager { if (res == null) { Log.wtf(TAG, "startInputOrWindowGainedFocus must not return" + " null. startInputReason=" - + InputMethodClient.getStartInputReason(startInputReason) + + InputMethodDebug.startInputReasonToString(startInputReason) + " editorInfo=" + tba + " controlFlags=#" + Integer.toHexString(controlFlags)); return false; @@ -1654,7 +1652,7 @@ public final class InputMethodManager { @UnsupportedAppUsage public void checkFocus() { if (checkFocusNoStartInput(false)) { - startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0); + startInputInner(StartInputReason.CHECK_FOCUS, null, 0, 0, 0); } } @@ -1717,7 +1715,7 @@ public final class InputMethodManager { boolean forceNewFocus = false; synchronized (mH) { if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView - + " softInputMode=" + InputMethodClient.softInputModeToString(softInputMode) + + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode) + " first=" + first + " flags=#" + Integer.toHexString(windowFlags)); if (mRestartOnNextWindowFocus) { @@ -1744,8 +1742,8 @@ public final class InputMethodManager { // should be done in conjunction with telling the system service // about the window gaining focus, to help make the transition // smooth. - if (startInputInner(InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN, - rootView.getWindowToken(), controlFlags, softInputMode, windowFlags)) { + if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), + controlFlags, softInputMode, windowFlags)) { return; } } @@ -1756,7 +1754,7 @@ public final class InputMethodManager { try { if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); mService.startInputOrWindowGainedFocus( - InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, + StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null, null, 0 /* missingMethodFlags */, rootView.getContext().getApplicationInfo().targetSdkVersion); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3dd6fd1410bd..66809dbc4e45 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -63,7 +63,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; -import android.graphics.fonts.Font; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.icu.text.DecimalFormatSymbols; import android.os.AsyncTask; @@ -2073,7 +2073,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName, @XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style, - @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) { + @IntRange(from = -1, to = FontStyle.FONT_WEIGHT_MAX) int weight) { if (typeface == null && familyName != null) { // Lookup normal Typeface from system font map. final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL); @@ -2100,9 +2100,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style, - @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) { + @IntRange(from = -1, to = FontStyle.FONT_WEIGHT_MAX) int weight) { if (weight >= 0) { - weight = Math.min(Font.FONT_WEIGHT_MAX, weight); + weight = Math.min(FontStyle.FONT_WEIGHT_MAX, weight); final boolean italic = (style & Typeface.ITALIC) != 0; setTypeface(Typeface.create(typeface, weight, italic)); } else { diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java new file mode 100644 index 000000000000..a5dc3d1b7138 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -0,0 +1,158 @@ +/* + * 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.internal.inputmethod; + +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams.SoftInputModeFlags; + +/** + * Provides useful methods for debugging. + */ +public final class InputMethodDebug { + /** + * Not intended to be instantiated. + */ + private InputMethodDebug() { + } + + /** + * Converts {@link StartInputReason} to {@link String} for debug logging. + * + * @param reason integer constant for {@link StartInputReason}. + * @return {@link String} message corresponds for the given {@code reason}. + */ + public static String startInputReasonToString(@StartInputReason int reason) { + switch (reason) { + case StartInputReason.UNSPECIFIED: + return "UNSPECIFIED"; + case StartInputReason.WINDOW_FOCUS_GAIN: + return "WINDOW_FOCUS_GAIN"; + case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY: + return "WINDOW_FOCUS_GAIN_REPORT_ONLY"; + case StartInputReason.APP_CALLED_RESTART_INPUT_API: + return "APP_CALLED_RESTART_INPUT_API"; + case StartInputReason.CHECK_FOCUS: + return "CHECK_FOCUS"; + case StartInputReason.BOUND_TO_IMMS: + return "BOUND_TO_IMMS"; + case StartInputReason.UNBOUND_FROM_IMMS: + return "UNBOUND_FROM_IMMS"; + case StartInputReason.ACTIVATED_BY_IMMS: + return "ACTIVATED_BY_IMMS"; + case StartInputReason.DEACTIVATED_BY_IMMS: + return "DEACTIVATED_BY_IMMS"; + case StartInputReason.SESSION_CREATED_BY_IME: + return "SESSION_CREATED_BY_IME"; + default: + return "Unknown=" + reason; + } + } + + /** + * Converts {@link UnbindReason} to {@link String} for debug logging. + * + * @param reason integer constant for {@link UnbindReason}. + * @return {@link String} message corresponds for the given {@code reason}. + */ + public static String unbindReasonToString(@UnbindReason int reason) { + switch (reason) { + case UnbindReason.UNSPECIFIED: + return "UNSPECIFIED"; + case UnbindReason.SWITCH_CLIENT: + return "SWITCH_CLIENT"; + case UnbindReason.SWITCH_IME: + return "SWITCH_IME"; + case UnbindReason.DISCONNECT_IME: + return "DISCONNECT_IME"; + case UnbindReason.NO_IME: + return "NO_IME"; + case UnbindReason.SWITCH_IME_FAILED: + return "SWITCH_IME_FAILED"; + case UnbindReason.SWITCH_USER: + return "SWITCH_USER"; + default: + return "Unknown=" + reason; + } + } + + /** + * Converts {@link SoftInputModeFlags} to {@link String} for debug logging. + * + * @param softInputMode integer constant for {@link SoftInputModeFlags}. + * @return {@link String} message corresponds for the given {@code softInputMode}. + */ + public static String softInputModeToString(@SoftInputModeFlags int softInputMode) { + final StringBuilder sb = new StringBuilder(); + final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; + final int adjust = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; + final boolean isForwardNav = + (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; + + switch (state) { + case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: + sb.append("STATE_UNSPECIFIED"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: + sb.append("STATE_UNCHANGED"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: + sb.append("STATE_HIDDEN"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: + sb.append("STATE_ALWAYS_HIDDEN"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: + sb.append("STATE_VISIBLE"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: + sb.append("STATE_ALWAYS_VISIBLE"); + break; + default: + sb.append("STATE_UNKNOWN("); + sb.append(state); + sb.append(")"); + break; + } + + switch (adjust) { + case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED: + sb.append("|ADJUST_UNSPECIFIED"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE: + sb.append("|ADJUST_RESIZE"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN: + sb.append("|ADJUST_PAN"); + break; + case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING: + sb.append("|ADJUST_NOTHING"); + break; + default: + sb.append("|ADJUST_UNKNOWN("); + sb.append(adjust); + sb.append(")"); + break; + } + + if (isForwardNav) { + // This is a special bit that is set by the system only during the window navigation. + sb.append("|IS_FORWARD_NAVIGATION"); + } + + return sb.toString(); + } +} diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java new file mode 100644 index 000000000000..a01c45919b8f --- /dev/null +++ b/core/java/com/android/internal/inputmethod/StartInputReason.java @@ -0,0 +1,92 @@ +/* + * 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.internal.inputmethod; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; + +/** + * Describes the reason why {@link android.view.inputmethod.InputMethodManager} is calling + * {@link com.android.internal.view.IInputMethodManager#startInputOrWindowGainedFocus}. + */ +@Retention(SOURCE) +@IntDef(value = { + StartInputReason.UNSPECIFIED, + StartInputReason.WINDOW_FOCUS_GAIN, + StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, + StartInputReason.APP_CALLED_RESTART_INPUT_API, + StartInputReason.CHECK_FOCUS, + StartInputReason.BOUND_TO_IMMS, + StartInputReason.UNBOUND_FROM_IMMS, + StartInputReason.ACTIVATED_BY_IMMS, + StartInputReason.DEACTIVATED_BY_IMMS, + StartInputReason.SESSION_CREATED_BY_IME}) +public @interface StartInputReason { + /** + * Reason is not specified. + */ + int UNSPECIFIED = 0; + /** + * {@link android.view.Window} gained focus and it made the focused {@link android.view.View} + * to (re)start a new connection. + */ + int WINDOW_FOCUS_GAIN = 1; + /** + * {@link android.view.Window} gained focus but there is no {@link android.view.View} that is + * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports + * this window focus change event. + */ + int WINDOW_FOCUS_GAIN_REPORT_ONLY = 2; + /** + * {@link android.view.inputmethod.InputMethodManager#restartInput(android.view.View)} is + * either explicitly called by the application or indirectly called by some Framework class + * (e.g. {@link android.widget.EditText}). + */ + int APP_CALLED_RESTART_INPUT_API = 3; + /** + * {@link android.view.View} requested a new connection because of view focus change. + */ + int CHECK_FOCUS = 4; + /** + * {@link android.view.inputmethod.InputMethodManager} is responding to + * {@link com.android.internal.view.IInputMethodClient#onBindMethod}. + */ + int BOUND_TO_IMMS = 5; + /** + * {@link android.view.inputmethod.InputMethodManager} is responding to + * {@link com.android.internal.view.IInputMethodClient#onUnbindMethod}. + */ + int UNBOUND_FROM_IMMS = 6; + /** + * {@link android.view.inputmethod.InputMethodManager} is responding to + * {@link com.android.internal.view.IInputMethodClient#setActive}. + */ + int ACTIVATED_BY_IMMS = 7; + /** + * {@link android.view.inputmethod.InputMethodManager} is responding to + * {@link com.android.internal.view.IInputMethodClient#setActive}. + */ + int DEACTIVATED_BY_IMMS = 8; + /** + * {@link com.android.server.inputmethod.InputMethodManagerService} is responding to + * {@link com.android.internal.view.IInputSessionCallback#sessionCreated}. + */ + int SESSION_CREATED_BY_IME = 9; +} diff --git a/core/java/com/android/internal/inputmethod/UnbindReason.java b/core/java/com/android/internal/inputmethod/UnbindReason.java new file mode 100644 index 000000000000..f0f18f11abe7 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/UnbindReason.java @@ -0,0 +1,69 @@ +/* + * 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.internal.inputmethod; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; + +/** + * Describes the reason why {@link com.android.server.inputmethod.InputMethodManagerService} is + * calling {@link com.android.internal.view.IInputMethodClient#onUnbindMethod}. + */ +@Retention(SOURCE) +@IntDef(value = { + UnbindReason.UNSPECIFIED, + UnbindReason.SWITCH_CLIENT, + UnbindReason.SWITCH_IME, + UnbindReason.DISCONNECT_IME, + UnbindReason.NO_IME, + UnbindReason.SWITCH_IME_FAILED, + UnbindReason.SWITCH_USER}) +public @interface UnbindReason { + /** + * Reason is not specified. + */ + int UNSPECIFIED = 0; + /** + * When a new IME client becomes active, the previous IME client will unbound from the current + * IME. + */ + int SWITCH_CLIENT = 1; + /** + * Before a new IME becomes active, the current IME client be unbound from the previous IME. + */ + int SWITCH_IME = 2; + /** + * When the current IME is disconnected, the current IME client will be unbound. + */ + int DISCONNECT_IME = 3; + /** + * When the system loses the last enabled IME, the current IME client will be unbound. + */ + int NO_IME = 4; + /** + * When the system failed to switch to another IME, the current IME client will be unbound. + */ + int SWITCH_IME_FAILED = 5; + /** + * When a new user becomes foreground, the previous IME client will be unbound from the previous + * user's active IME. + */ + int SWITCH_USER = 6; +} diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl index 2618356d7a09..17b2bc46de36 100644 --- a/core/java/com/android/internal/view/IInputMethodClient.aidl +++ b/core/java/com/android/internal/view/IInputMethodClient.aidl @@ -24,7 +24,6 @@ import com.android.internal.view.InputBindResult; */ oneway interface IInputMethodClient { void onBindMethod(in InputBindResult res); - // unbindReason corresponds to InputMethodClient.UnbindReason. void onUnbindMethod(int sequence, int unbindReason); void setActive(boolean active, boolean fullscreen); void reportFullscreenMode(boolean fullscreen); diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 34e850130b50..29c55c234677 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -54,7 +54,7 @@ interface IInputMethodManager { // has gained focus, and if 'attribute' is non-null then also does startInput. // @NonNull InputBindResult startInputOrWindowGainedFocus( - /* @InputMethodClient.StartInputReason */ int startInputReason, + /* @StartInputReason */ int startInputReason, in IInputMethodClient client, in IBinder windowToken, int controlFlags, /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode, int windowFlags, in EditorInfo attribute, IInputContext inputContext, diff --git a/core/java/com/android/internal/view/InputMethodClient.java b/core/java/com/android/internal/view/InputMethodClient.java deleted file mode 100644 index bbd33a258e18..000000000000 --- a/core/java/com/android/internal/view/InputMethodClient.java +++ /dev/null @@ -1,169 +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. - */ - -package com.android.internal.view; - -import android.annotation.IntDef; -import android.view.WindowManager.LayoutParams; -import android.view.WindowManager.LayoutParams.SoftInputModeFlags; - -import java.lang.annotation.Retention; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -public final class InputMethodClient { - public static final int START_INPUT_REASON_UNSPECIFIED = 0; - public static final int START_INPUT_REASON_WINDOW_FOCUS_GAIN = 1; - public static final int START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY = 2; - public static final int START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API = 3; - public static final int START_INPUT_REASON_CHECK_FOCUS = 4; - public static final int START_INPUT_REASON_BOUND_TO_IMMS = 5; - public static final int START_INPUT_REASON_UNBOUND_FROM_IMMS = 6; - public static final int START_INPUT_REASON_ACTIVATED_BY_IMMS = 7; - public static final int START_INPUT_REASON_DEACTIVATED_BY_IMMS = 8; - public static final int START_INPUT_REASON_SESSION_CREATED_BY_IME = 9; - - @Retention(SOURCE) - @IntDef({START_INPUT_REASON_UNSPECIFIED, START_INPUT_REASON_WINDOW_FOCUS_GAIN, - START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, - START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, START_INPUT_REASON_CHECK_FOCUS, - START_INPUT_REASON_BOUND_TO_IMMS, START_INPUT_REASON_ACTIVATED_BY_IMMS, - START_INPUT_REASON_DEACTIVATED_BY_IMMS, START_INPUT_REASON_SESSION_CREATED_BY_IME}) - public @interface StartInputReason {} - - public static String getStartInputReason(@StartInputReason final int reason) { - switch (reason) { - case START_INPUT_REASON_UNSPECIFIED: - return "UNSPECIFIED"; - case START_INPUT_REASON_WINDOW_FOCUS_GAIN: - return "WINDOW_FOCUS_GAIN"; - case START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY: - return "WINDOW_FOCUS_GAIN_REPORT_ONLY"; - case START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API: - return "APP_CALLED_RESTART_INPUT_API"; - case START_INPUT_REASON_CHECK_FOCUS: - return "CHECK_FOCUS"; - case START_INPUT_REASON_BOUND_TO_IMMS: - return "BOUND_TO_IMMS"; - case START_INPUT_REASON_UNBOUND_FROM_IMMS: - return "UNBOUND_FROM_IMMS"; - case START_INPUT_REASON_ACTIVATED_BY_IMMS: - return "ACTIVATED_BY_IMMS"; - case START_INPUT_REASON_DEACTIVATED_BY_IMMS: - return "DEACTIVATED_BY_IMMS"; - case START_INPUT_REASON_SESSION_CREATED_BY_IME: - return "SESSION_CREATED_BY_IME"; - default: - return "Unknown=" + reason; - } - } - - public static final int UNBIND_REASON_UNSPECIFIED = 0; - public static final int UNBIND_REASON_SWITCH_CLIENT = 1; - public static final int UNBIND_REASON_SWITCH_IME = 2; - public static final int UNBIND_REASON_DISCONNECT_IME = 3; - public static final int UNBIND_REASON_NO_IME = 4; - public static final int UNBIND_REASON_SWITCH_IME_FAILED = 5; - public static final int UNBIND_REASON_SWITCH_USER = 6; - - @Retention(SOURCE) - @IntDef({UNBIND_REASON_UNSPECIFIED, UNBIND_REASON_SWITCH_CLIENT, UNBIND_REASON_SWITCH_IME, - UNBIND_REASON_DISCONNECT_IME, UNBIND_REASON_NO_IME, UNBIND_REASON_SWITCH_IME_FAILED, - UNBIND_REASON_SWITCH_USER}) - public @interface UnbindReason {} - - public static String getUnbindReason(@UnbindReason final int reason) { - switch (reason) { - case UNBIND_REASON_UNSPECIFIED: - return "UNSPECIFIED"; - case UNBIND_REASON_SWITCH_CLIENT: - return "SWITCH_CLIENT"; - case UNBIND_REASON_SWITCH_IME: - return "SWITCH_IME"; - case UNBIND_REASON_DISCONNECT_IME: - return "DISCONNECT_IME"; - case UNBIND_REASON_NO_IME: - return "NO_IME"; - case UNBIND_REASON_SWITCH_IME_FAILED: - return "SWITCH_IME_FAILED"; - case UNBIND_REASON_SWITCH_USER: - return "SWITCH_USER"; - default: - return "Unknown=" + reason; - } - } - - public static String softInputModeToString(@SoftInputModeFlags final int softInputMode) { - final StringBuilder sb = new StringBuilder(); - final int state = softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE; - final int adjust = softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST; - final boolean isForwardNav = - (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; - - switch (state) { - case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: - sb.append("STATE_UNSPECIFIED"); - break; - case LayoutParams.SOFT_INPUT_STATE_UNCHANGED: - sb.append("STATE_UNCHANGED"); - break; - case LayoutParams.SOFT_INPUT_STATE_HIDDEN: - sb.append("STATE_HIDDEN"); - break; - case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: - sb.append("STATE_ALWAYS_HIDDEN"); - break; - case LayoutParams.SOFT_INPUT_STATE_VISIBLE: - sb.append("STATE_VISIBLE"); - break; - case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: - sb.append("STATE_ALWAYS_VISIBLE"); - break; - default: - sb.append("STATE_UNKNOWN("); - sb.append(state); - sb.append(")"); - break; - } - - switch (adjust) { - case LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED: - sb.append("|ADJUST_UNSPECIFIED"); - break; - case LayoutParams.SOFT_INPUT_ADJUST_RESIZE: - sb.append("|ADJUST_RESIZE"); - break; - case LayoutParams.SOFT_INPUT_ADJUST_PAN: - sb.append("|ADJUST_PAN"); - break; - case LayoutParams.SOFT_INPUT_ADJUST_NOTHING: - sb.append("|ADJUST_NOTHING"); - break; - default: - sb.append("|ADJUST_UNKNOWN("); - sb.append(adjust); - sb.append(")"); - break; - } - - if (isForwardNav) { - // This is a special bit that is set by the system only during the window navigation. - sb.append("|IS_FORWARD_NAVIGATION"); - } - - return sb.toString(); - } -} diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index fa4406185218..9ea82a9b9c2e 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2924,55 +2924,55 @@ <!-- Title for EditText context menu [CHAR LIMIT=20] --> <string name="editTextMenuTitle">Text actions</string> - <!-- Label for item in the text selection menu to trigger an Email app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger an Email app. Should be a verb. [CHAR LIMIT=30] --> <string name="email">Email</string> <!-- Accessibility description for an item in the text selection menu to trigger an Email app [CHAR LIMIT=NONE] --> <string name="email_desc">Email selected address</string> - <!-- Label for item in the text selection menu to trigger a Dialer app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger a Dialer app. Should be a verb. [CHAR LIMIT=30] --> <string name="dial">Call</string> <!-- Accessibility description for an item in the text selection menu to call a phone number [CHAR LIMIT=NONE] --> <string name="dial_desc">Call selected phone number</string> - <!-- Label for item in the text selection menu to trigger a Map app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger a Map app. Should be a verb. [CHAR LIMIT=30] --> <string name="map">Map</string> <!-- Accessibility description for an item in the text selection menu to open maps for an address [CHAR LIMIT=NONE] --> <string name="map_desc">Locate selected address</string> - <!-- Label for item in the text selection menu to trigger a Browser app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger a Browser app. Should be a verb. [CHAR LIMIT=30] --> <string name="browse">Open</string> <!-- Accessibility description for an item in the text selection menu to open a URL in a browser [CHAR LIMIT=NONE] --> <string name="browse_desc">Open selected URL</string> - <!-- Label for item in the text selection menu to trigger an SMS app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger an SMS app. Should be a verb. [CHAR LIMIT=30] --> <string name="sms">Message</string> <!-- Accessibility description for an item in the text selection menu to send an SMS to a phone number [CHAR LIMIT=NONE] --> <string name="sms_desc">Message selected phone number</string> - <!-- Label for item in the text selection menu to trigger adding a contact. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger adding a contact. Should be a verb. [CHAR LIMIT=30] --> <string name="add_contact">Add</string> <!-- Accessibility description for an item in the text selection menu to add the selected detail to contacts [CHAR LIMIT=NONE] --> <string name="add_contact_desc">Add to contacts</string> - <!-- Label for item in the text selection menu to view the calendar for the selected time/date. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to view the calendar for the selected time/date. Should be a verb. [CHAR LIMIT=30] --> <string name="view_calendar">View</string> <!-- Accessibility description for an item in the text selection menu to view the calendar for a date [CHAR LIMIT=NONE]--> <string name="view_calendar_desc">View selected time in calendar</string> - <!-- Label for item in the text selection menu to create a calendar event at the selected time/date. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to create a calendar event at the selected time/date. Should be a verb. [CHAR LIMIT=30] --> <string name="add_calendar_event">Schedule</string> <!-- Accessibility description for an item in the text selection menu to schedule an event for a date [CHAR LIMIT=NONE] --> <string name="add_calendar_event_desc">Schedule event for selected time</string> - <!-- Label for item in the text selection menu to track a selected flight number. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to track a selected flight number. Should be a verb. [CHAR LIMIT=30] --> <string name="view_flight">Track</string> <!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] --> diff --git a/core/tests/coretests/assets/fonts/1em_bidi_font.ttf b/core/tests/coretests/assets/fonts/1em_bidi_font.ttf Binary files differnew file mode 100644 index 000000000000..459925433349 --- /dev/null +++ b/core/tests/coretests/assets/fonts/1em_bidi_font.ttf diff --git a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java new file mode 100644 index 000000000000..1208d7ca194a --- /dev/null +++ b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java @@ -0,0 +1,166 @@ +/* + * 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 android.text; + +import static org.junit.Assert.assertArrayEquals; + +import android.content.Context; +import android.graphics.Path; +import android.graphics.Typeface; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.text.method.MetaKeyKeyListener; +import android.view.KeyEvent; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class LayoutBidiCursorPathTest { + + private static final float BIDI_TEXT_SIZE = 12f; + private static final String LTR_TEXT = "hello"; + private static final String RTL_TEXT = "Ù…Ø±ØØ¨Ø§"; + + private SpannableStringBuilder mBidiText; + private TextPaint mTextPaint; + + @Before + public void setup() { + mBidiText = new SpannableStringBuilder(LTR_TEXT + RTL_TEXT); + + final Context context = InstrumentationRegistry.getTargetContext(); + mTextPaint = new TextPaint(); + mTextPaint.setTypeface( + Typeface.createFromAsset(context.getAssets(), "fonts/1em_bidi_font.ttf")); + mTextPaint.setTextSize(BIDI_TEXT_SIZE); + } + + @Test + public void testGetCursorPathSegments() { + // Setup layout and Act. + final Path actualPath = new Path(); + setupLayoutAndGetCursorPath(actualPath); + + // Expected path. + final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; + final int top = 0; + // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. + final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); + + final Path expectedPath = new Path(); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1, bottom); + + // Assert. + assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); + } + + @Test + public void testGetCursorPath_whenShiftIsPressed() { + // When shift is pressed a triangle is drawn at the bottom quarter of the cursor. + // Set up key. + final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; + metaKeyKeyListener + .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_SHIFT_RIGHT, null /*keyEvent*/); + + // Setup layout and Act. + final Path actualPath = new Path(); + setupLayoutAndGetCursorPath(actualPath); + + // Expected path. + final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; + final int top = 0; + // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. + int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); + // Draw a triangle at the bottom quarter of the cursor, thus cut the cursor to its 3/4 + // length. + final int dist = (bottom - top) / 4; + bottom -= dist; + + final Path expectedPath = new Path(); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1, bottom); + + expectedPath.moveTo(h1, bottom); + expectedPath.lineTo(h1 - dist, bottom + dist); + + expectedPath.moveTo(h1 - dist, bottom + dist - 0.5f); + expectedPath.lineTo(h1 + dist, bottom + dist - 0.5f); + + expectedPath.moveTo(h1 + dist, bottom + dist); + expectedPath.lineTo(h1, bottom); + + // Assert. + assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); + } + + @Test + public void testGetCursorPath_whenAltIsPressed() { + // When alt is pressed a triangle is drawn at the top quarter of the cursor. + // Set up key. + final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; + metaKeyKeyListener + .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_ALT_RIGHT, null /*keyEvent*/); + + // Setup layout and Act. + final Path actualPath = new Path(); + setupLayoutAndGetCursorPath(actualPath); + + // Expected path. + final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; + int top = 0; + // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. + final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); + // Draw a triangle at the top quarter of the cursor, thus cut the cursor to its 3/4 length. + final int dist = (bottom - top) / 4; + top += dist; + + final Path expectedPath = new Path(); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1, bottom); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1 - dist, top - dist); + + expectedPath.moveTo(h1 - dist, top - dist + 0.5f); + expectedPath.lineTo(h1 + dist, top - dist + 0.5f); + + expectedPath.moveTo(h1 + dist, top - dist); + expectedPath.lineTo(h1, top); + + // Assert. + assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); + } + + private void setupLayoutAndGetCursorPath(Path path) { + final Layout layout = StaticLayout.Builder.obtain( + mBidiText, 0, mBidiText.length(), mTextPaint, Integer.MAX_VALUE) + .setIncludePad(false) + .build(); + + layout.getCursorPath(LTR_TEXT.length(), path, mBidiText); + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 7ad207f339d1..ba47300210cd 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -27,6 +27,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.net.Uri; @@ -148,7 +149,7 @@ public class Typeface { @UnsupportedAppUsage private @Style int mStyle = 0; - private @IntRange(from = 0, to = android.graphics.fonts.Font.FONT_WEIGHT_MAX) int mWeight = 0; + private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) int mWeight = 0; // Value for weight and italic. Indicates the value is resolved by font metadata. // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index bd1ac25bf8df..f426b2d3465b 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -51,61 +51,6 @@ public final class Font { private static final int STYLE_NORMAL = 0; /** - * A minimum weight value for the font - */ - public static final int FONT_WEIGHT_MIN = 1; - - /** - * A font weight value for the thin weight - */ - public static final int FONT_WEIGHT_THIN = 100; - - /** - * A font weight value for the extra-light weight - */ - public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; - - /** - * A font weight value for the light weight - */ - public static final int FONT_WEIGHT_LIGHT = 300; - - /** - * A font weight value for the normal weight - */ - public static final int FONT_WEIGHT_NORMAL = 400; - - /** - * A font weight value for the medium weight - */ - public static final int FONT_WEIGHT_MEDIUM = 500; - - /** - * A font weight value for the semi-bold weight - */ - public static final int FONT_WEIGHT_SEMI_BOLD = 600; - - /** - * A font weight value for the bold weight. - */ - public static final int FONT_WEIGHT_BOLD = 700; - - /** - * A font weight value for the extra-bold weight - */ - public static final int FONT_WEIGHT_EXTRA_BOLD = 800; - - /** - * A font weight value for the black weight - */ - public static final int FONT_WEIGHT_BLACK = 900; - - /** - * A maximum weight value for the font - */ - public static final int FONT_WEIGHT_MAX = 1000; - - /** * A builder class for creating new Font. */ public static class Builder { @@ -275,66 +220,68 @@ public final class Font { * <tr> * <td align="center">100</td> * <td align="center">Thin</td> - * <td align="center">{@link Font#FONT_WEIGHT_THIN}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_THIN}</td> * </tr> * <tr> * <td align="center">200</td> * <td align="center">Extra Light (Ultra Light)</td> - * <td align="center">{@link Font#FONT_WEIGHT_EXTRA_LIGHT}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_LIGHT}</td> * </tr> * <tr> * <td align="center">300</td> * <td align="center">Light</td> - * <td align="center">{@link Font#FONT_WEIGHT_LIGHT}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_LIGHT}</td> * </tr> * <tr> * <td align="center">400</td> * <td align="center">Normal (Regular)</td> - * <td align="center">{@link Font#FONT_WEIGHT_NORMAL}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_NORMAL}</td> * </tr> * <tr> * <td align="center">500</td> * <td align="center">Medium</td> - * <td align="center">{@link Font#FONT_WEIGHT_MEDIUM}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_MEDIUM}</td> * </tr> * <tr> * <td align="center">600</td> * <td align="center">Semi Bold (Demi Bold)</td> - * <td align="center">{@link Font#FONT_WEIGHT_SEMI_BOLD}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_SEMI_BOLD}</td> * </tr> * <tr> * <td align="center">700</td> * <td align="center">Bold</td> - * <td align="center">{@link Font#FONT_WEIGHT_BOLD}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BOLD}</td> * </tr> * <tr> * <td align="center">800</td> * <td align="center">Extra Bold (Ultra Bold)</td> - * <td align="center">{@link Font#FONT_WEIGHT_EXTRA_BOLD}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_BOLD}</td> * </tr> * <tr> * <td align="center">900</td> * <td align="center">Black (Heavy)</td> - * <td align="center">{@link Font#FONT_WEIGHT_BLACK}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BLACK}</td> * </tr> * </tbody> * </p> * - * @see Font#FONT_WEIGHT_THIN - * @see Font#FONT_WEIGHT_EXTRA_LIGHT - * @see Font#FONT_WEIGHT_LIGHT - * @see Font#FONT_WEIGHT_NORMAL - * @see Font#FONT_WEIGHT_MEDIUM - * @see Font#FONT_WEIGHT_SEMI_BOLD - * @see Font#FONT_WEIGHT_BOLD - * @see Font#FONT_WEIGHT_EXTRA_BOLD - * @see Font#FONT_WEIGHT_BLACK + * @see FontStyle#FONT_WEIGHT_THIN + * @see FontStyle#FONT_WEIGHT_EXTRA_LIGHT + * @see FontStyle#FONT_WEIGHT_LIGHT + * @see FontStyle#FONT_WEIGHT_NORMAL + * @see FontStyle#FONT_WEIGHT_MEDIUM + * @see FontStyle#FONT_WEIGHT_SEMI_BOLD + * @see FontStyle#FONT_WEIGHT_BOLD + * @see FontStyle#FONT_WEIGHT_EXTRA_BOLD + * @see FontStyle#FONT_WEIGHT_BLACK * @param weight a weight value * @return this builder */ public @NonNull Builder setWeight( - @IntRange(from = FONT_WEIGHT_MIN, to = FONT_WEIGHT_MAX) int weight) { - Preconditions.checkArgument(FONT_WEIGHT_MIN <= weight && weight <= FONT_WEIGHT_MAX); + @IntRange(from = FontStyle.FONT_WEIGHT_MIN, to = FontStyle.FONT_WEIGHT_MAX) + int weight) { + Preconditions.checkArgument( + FontStyle.FONT_WEIGHT_MIN <= weight && weight <= FontStyle.FONT_WEIGHT_MAX); mWeight = weight; return this; } @@ -346,13 +293,12 @@ public final class Font { * will resolve the style by reading font tables. * * For example, if you want to use italic font as upright font, call {@code - * setItalic(false)} explicitly. + * setSlant(false)} explicitly. * - * @param italic {@code true} if the font is italic. Otherwise {@code false}. * @return this builder */ - public @NonNull Builder setItalic(boolean italic) { - mItalic = italic ? STYLE_ITALIC : STYLE_NORMAL; + public @NonNull Builder setSlant(@FontStyle.FontSlant int slant) { + mItalic = slant == FontStyle.FONT_SLANT_UPRIGHT ? STYLE_NORMAL : STYLE_ITALIC; return this; } @@ -414,8 +360,11 @@ public final class Font { mItalic = STYLE_NORMAL; } } - mWeight = Math.max(FONT_WEIGHT_MIN, Math.min(FONT_WEIGHT_MAX, mWeight)); + mWeight = Math.max(FontStyle.FONT_WEIGHT_MIN, + Math.min(FontStyle.FONT_WEIGHT_MAX, mWeight)); final boolean italic = (mItalic == STYLE_ITALIC); + final int slant = (mItalic == STYLE_ITALIC) + ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT; final long builderPtr = nInitBuilder(); if (mAxes != null) { for (FontVariationAxis axis : mAxes) { @@ -424,8 +373,8 @@ public final class Font { } final ByteBuffer readonlyBuffer = mBuffer.asReadOnlyBuffer(); final long ptr = nBuild(builderPtr, readonlyBuffer, mWeight, italic, mTtcIndex); - final Font font = new Font(ptr, readonlyBuffer, mFile, mWeight, italic, mTtcIndex, - mAxes, mLocaleList); + final Font font = new Font(ptr, readonlyBuffer, mFile, + new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList); sFontRegistory.registerNativeAllocation(font, ptr); return font; } @@ -454,8 +403,7 @@ public final class Font { private final long mNativePtr; // address of the shared ptr of minikin::Font private final @NonNull ByteBuffer mBuffer; private final @Nullable File mFile; - private final @IntRange(from = 0, to = 1000) int mWeight; - private final boolean mItalic; + private final FontStyle mFontStyle; private final @IntRange(from = 0) int mTtcIndex; private final @Nullable FontVariationAxis[] mAxes; private final @NonNull String mLocaleList; @@ -464,13 +412,11 @@ public final class Font { * Use Builder instead */ private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file, - @IntRange(from = 0, to = 1000) int weight, boolean italic, - @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes, - @NonNull String localeList) { + @NonNull FontStyle fontStyle, @IntRange(from = 0) int ttcIndex, + @Nullable FontVariationAxis[] axes, @NonNull String localeList) { mBuffer = buffer; mFile = file; - mWeight = weight; - mItalic = italic; + mFontStyle = fontStyle; mNativePtr = nativePtr; mTtcIndex = ttcIndex; mAxes = axes; @@ -504,17 +450,17 @@ public final class Font { * @return a weight value */ public @IntRange(from = 0, to = 1000)int getWeight() { - return mWeight; + return mFontStyle.getWeight(); } /** - * Returns true if this font is marked as italic, otherwise returns false. + * Get a slant value associated with this font. * - * @see Builder#setItalic(boolean) - * @return true if italic, otherwise false + * @see Builder#setSlant(boolean) + * @return a slant value */ - public boolean isItalic() { - return mItalic; + public @FontStyle.FontSlant int getSlant() { + return mFontStyle.getSlant(); } /** @@ -564,21 +510,20 @@ public final class Font { return false; } Font f = (Font) o; - return f.mWeight == mWeight && f.mItalic == mItalic && f.mTtcIndex == mTtcIndex + return mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer); } @Override public int hashCode() { - return Objects.hash(mWeight, mItalic, mTtcIndex, Arrays.hashCode(mAxes), mBuffer); + return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer); } @Override public String toString() { return "Font {" + "path=" + mFile - + ", weight=" + mWeight - + ", italic=" + mItalic + + ", style=" + mFontStyle + ", ttcIndex=" + mTtcIndex + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes) + ", localeList=" + mLocaleList diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java index 3bcdc31a3160..52a37da47cff 100644 --- a/graphics/java/android/graphics/fonts/FontFamily.java +++ b/graphics/java/android/graphics/fonts/FontFamily.java @@ -124,7 +124,7 @@ public final class FontFamily { } private static int makeStyleIdentifier(@NonNull Font font) { - return font.getWeight() | (font.isItalic() ? (1 << 16) : 0); + return font.getWeight() | (font.getSlant() << 16); } private static native long nInitBuilder(); diff --git a/graphics/java/android/graphics/fonts/FontStyle.java b/graphics/java/android/graphics/fonts/FontStyle.java new file mode 100644 index 000000000000..82fc7ac01772 --- /dev/null +++ b/graphics/java/android/graphics/fonts/FontStyle.java @@ -0,0 +1,256 @@ +/* + * 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 android.graphics.fonts; + +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.Nullable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * A font style object. + * + * This class represents a single font style which is a pair of weight value and slant value. + * Here are common font styles examples: + * <p> + * <pre> + * <code> + * final FontStyle NORMAL = new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT); + * final FontStyle BOLD = new FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_UPRIGHT); + * final FontStyle ITALIC = new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC); + * final FontStyle BOLD_ITALIC = new FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_ITALIC); + * </code> + * </pre> + * </p> + * + */ +public final class FontStyle { + private static final String TAG = "FontStyle"; + + /** + * A minimum weight value for the font + */ + public static final int FONT_WEIGHT_MIN = 1; + + /** + * A font weight value for the thin weight + */ + public static final int FONT_WEIGHT_THIN = 100; + + /** + * A font weight value for the extra-light weight + */ + public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; + + /** + * A font weight value for the light weight + */ + public static final int FONT_WEIGHT_LIGHT = 300; + + /** + * A font weight value for the normal weight + */ + public static final int FONT_WEIGHT_NORMAL = 400; + + /** + * A font weight value for the medium weight + */ + public static final int FONT_WEIGHT_MEDIUM = 500; + + /** + * A font weight value for the semi-bold weight + */ + public static final int FONT_WEIGHT_SEMI_BOLD = 600; + + /** + * A font weight value for the bold weight. + */ + public static final int FONT_WEIGHT_BOLD = 700; + + /** + * A font weight value for the extra-bold weight + */ + public static final int FONT_WEIGHT_EXTRA_BOLD = 800; + + /** + * A font weight value for the black weight + */ + public static final int FONT_WEIGHT_BLACK = 900; + + /** + * A maximum weight value for the font + */ + public static final int FONT_WEIGHT_MAX = 1000; + + /** + * A font slant value for upright + */ + public static final int FONT_SLANT_UPRIGHT = 0; + + /** + * A font slant value for italic + */ + public static final int FONT_SLANT_ITALIC = 1; + + // TODO: Support FONT_SLANT_OBLIQUE + + /** @hide */ + @IntDef(prefix = { "FONT_SLANT_" }, value = { + FONT_SLANT_UPRIGHT, + FONT_SLANT_ITALIC + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FontSlant {} + + private final @IntRange(from = 0, to = 1000) int mWeight; + private final @FontSlant int mSlant; + // TODO: Support width + + public FontStyle() { + mWeight = FONT_WEIGHT_NORMAL; + mSlant = FONT_SLANT_UPRIGHT; + } + + /** + * Create FontStyle with specific weight and italic + * + * <p> + * <table> + * <thead> + * <tr> + * <th align="center">Value</th> + * <th align="center">Name</th> + * <th align="center">Android Definition</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">100</td> + * <td align="center">Thin</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_THIN}</td> + * </tr> + * <tr> + * <td align="center">200</td> + * <td align="center">Extra Light (Ultra Light)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_LIGHT}</td> + * </tr> + * <tr> + * <td align="center">300</td> + * <td align="center">Light</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_LIGHT}</td> + * </tr> + * <tr> + * <td align="center">400</td> + * <td align="center">Normal (Regular)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_NORMAL}</td> + * </tr> + * <tr> + * <td align="center">500</td> + * <td align="center">Medium</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_MEDIUM}</td> + * </tr> + * <tr> + * <td align="center">600</td> + * <td align="center">Semi Bold (Demi Bold)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_SEMI_BOLD}</td> + * </tr> + * <tr> + * <td align="center">700</td> + * <td align="center">Bold</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BOLD}</td> + * </tr> + * <tr> + * <td align="center">800</td> + * <td align="center">Extra Bold (Ultra Bold)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_BOLD}</td> + * </tr> + * <tr> + * <td align="center">900</td> + * <td align="center">Black (Heavy)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BLACK}</td> + * </tr> + * </tbody> + * </p> + * + * @see FontStyle#FONT_WEIGHT_THIN + * @see FontStyle#FONT_WEIGHT_EXTRA_LIGHT + * @see FontStyle#FONT_WEIGHT_LIGHT + * @see FontStyle#FONT_WEIGHT_NORMAL + * @see FontStyle#FONT_WEIGHT_MEDIUM + * @see FontStyle#FONT_WEIGHT_SEMI_BOLD + * @see FontStyle#FONT_WEIGHT_BOLD + * @see FontStyle#FONT_WEIGHT_EXTRA_BOLD + * @see FontStyle#FONT_WEIGHT_BLACK + * @param weight a weight value + * @param slant a slant value + */ + public FontStyle(int weight, @FontSlant int slant) { + Preconditions.checkArgument(FONT_WEIGHT_MIN <= weight && weight <= FONT_WEIGHT_MAX, + "weight value must be [" + FONT_WEIGHT_MIN + ", " + FONT_WEIGHT_MAX + "]"); + Preconditions.checkArgument(slant == FONT_SLANT_UPRIGHT || slant == FONT_SLANT_ITALIC, + "slant value must be FONT_SLANT_UPRIGHT or FONT_SLANT_UPRIGHT"); + mWeight = weight; + mSlant = slant; + } + + + /** + * Gets the weight value + * + * @see FontStyle#setWeight(int) + * @return a weight value + */ + public @IntRange(from = 0, to = 1000) int getWeight() { + return mWeight; + } + + /** + * Gets the slant value + * + * @return a slant value + */ + public @FontSlant int getSlant() { + return mSlant; + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + if (o == null || !(o instanceof FontStyle)) { + return false; + } + FontStyle fontStyle = (FontStyle) o; + return fontStyle.mWeight == mWeight && fontStyle.mSlant == mSlant; + } + + @Override + public int hashCode() { + return Objects.hash(mWeight, mSlant); + } + + @Override + public String toString() { + return "FontStyle { weight=" + mWeight + ", slant=" + mSlant + "}"; + } +} diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 2d21bbbd4e43..750adb2757c8 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -192,7 +192,8 @@ public final class SystemFonts { try { font = new Font.Builder(buffer, new File(fullPath), languageTags) .setWeight(fontConfig.getWeight()) - .setItalic(fontConfig.isItalic()) + .setSlant(fontConfig.isItalic() ? FontStyle.FONT_SLANT_ITALIC + : FontStyle.FONT_SLANT_UPRIGHT) .setTtcIndex(fontConfig.getTtcIndex()) .setFontVariationSettings(fontConfig.getAxes()) .build(); diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 503951d1adc6..f0053a48ae3d 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -231,6 +231,9 @@ cc_defaults { "protos/graphicsstats.proto", ], + // Allow implicit fallthroughs in HardwareBitmapUploader.cpp until they are fixed. + cflags: ["-Wno-implicit-fallthrough"], + proto: { export_proto_headers: true, }, diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index 0022c931c45e..c6e4c154b41e 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -141,7 +141,7 @@ uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) { // select only flags that might affect text layout flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag | - SkPaint::kAutoHinting_Flag | SkPaint::kVerticalText_Flag); + SkPaint::kAutoHinting_Flag); flags |= (hinting << 16); return flags; } diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index e3c97ce686d9..524dfb0fe4ef 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -288,7 +288,7 @@ void parseOptions(int argc, char* argv[]) { case '?': fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]); - // fall-through + [[fallthrough]]; default: error = true; break; diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index e67b100d840d..474b671c0c2b 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -538,8 +538,13 @@ public class MtpDatabase implements AutoCloseable { MtpPropertyGroup propertyGroup; for (MtpStorageManager.MtpObject obj : objs) { if (property == 0xffffffff) { + if (format == 0 && handle != 0 && handle != 0xffffffff) { + // return properties based on the object's format + format = obj.getFormat(); + } // Get all properties supported by this object - propertyGroup = mPropertyGroupsByFormat.get(obj.getFormat()); + // format should be the same between get & put + propertyGroup = mPropertyGroupsByFormat.get(format); if (propertyGroup == null) { int[] propertyList = getSupportedObjectProperties(format); propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName, diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 3870124f295e..fa9ab1f72688 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -128,6 +128,7 @@ cc_library_shared { "libmediametrics", "libmediaplayer2", "libmediaplayer2-protos", + "libmediandk_utils", "libmediautils", "libnetd_client", // for setNetworkForUser "libprotobuf-cpp-lite", diff --git a/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java b/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java index 5782ea100070..31c9224a8489 100644 --- a/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java @@ -66,7 +66,7 @@ public class AgingHelper { public void onNotificationSeen(NotificationEntry entry) { // user has strong opinions about this notification. we can't down rank it, so don't bother. - if (entry.getChannel().isImportanceLocked()) { + if (entry.getChannel().hasUserSetImportance()) { return; } diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index 3333e1592bfa..8f33a7016b39 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -25,7 +25,6 @@ import static android.service.notification.NotificationListenerService.Ranking import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; -import android.app.AlarmManager; import android.app.INotificationManager; import android.app.Notification; import android.app.NotificationChannel; @@ -224,8 +223,9 @@ public class Assistant extends NotificationAssistantService { } /** A convenience helper for creating an adjustment for an SBN. */ + @VisibleForTesting @Nullable - private Adjustment createEnqueuedNotificationAdjustment( + Adjustment createEnqueuedNotificationAdjustment( @NonNull NotificationEntry entry, @NonNull ArrayList<Notification.Action> smartActions, @NonNull ArrayList<CharSequence> smartReplies) { @@ -237,7 +237,9 @@ public class Assistant extends NotificationAssistantService { signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies); } if (mNotificationCategorizer.shouldSilence(entry)) { - signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); + final int importance = entry.getImportance() < IMPORTANCE_LOW ? entry.getImportance() + : IMPORTANCE_LOW; + signals.putInt(KEY_IMPORTANCE, importance); } return new Adjustment( diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java index 2820232cdb38..2eb005a9b1fa 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java @@ -66,6 +66,7 @@ import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; +import java.util.ArrayList; public class AssistantTest extends ServiceTestCase<Assistant> { @@ -466,4 +467,12 @@ public class AssistantTest extends ServiceTestCase<Assistant> { assertFalse(mAssistant.mLiveNotifications.containsKey(sbn.getKey())); } + + @Test + public void testAssistantNeverIncreasesImportanceWhenSuggestingSilent() throws Exception { + StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C3, "min notif!", null); + Adjustment adjust = mAssistant.createEnqueuedNotificationAdjustment(new NotificationEntry( + mPackageManager, sbn, P1C3), new ArrayList<>(), new ArrayList<>()); + assertEquals(IMPORTANCE_MIN, adjust.getSignals().getInt(Adjustment.KEY_IMPORTANCE)); + } } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index b2be5e6b5f8e..793a1778f900 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -1270,26 +1270,36 @@ public class VibratorService extends IVibratorService.Stub public int onCommand(String cmd) { if ("vibrate".equals(cmd)) { return runVibrate(); + } else if ("prebaked".equals(cmd)) { + return runPrebaked(); } return handleDefaultCommands(cmd); } + private boolean checkDoNotDisturb() { + try { + final int zenMode = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ZEN_MODE); + if (zenMode != Settings.Global.ZEN_MODE_OFF) { + try (PrintWriter pw = getOutPrintWriter();) { + pw.print("Ignoring because device is on DND mode "); + pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_", + zenMode)); + return true; + } + } + } catch (SettingNotFoundException e) { + // ignore + } + + return false; + } + private int runVibrate() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate"); try { - try { - final int zenMode = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ZEN_MODE); - if (zenMode != Settings.Global.ZEN_MODE_OFF) { - try (PrintWriter pw = getOutPrintWriter();) { - pw.print("Ignoring because device is on DND mode "); - pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_", - zenMode)); - return 0; - } - } - } catch (SettingNotFoundException e) { - // ignore + if (checkDoNotDisturb()) { + return 0; } final long duration = Long.parseLong(getNextArgRequired()); @@ -1311,6 +1321,30 @@ public class VibratorService extends IVibratorService.Stub } } + private int runPrebaked() { + Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked"); + try { + if (checkDoNotDisturb()) { + return 0; + } + + final int id = Integer.parseInt(getNextArgRequired()); + + String description = getNextArg(); + if (description == null) { + description = "Shell command"; + } + + VibrationEffect effect = + VibrationEffect.get(id, false); + vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN, + "Shell Command", mToken); + return 0; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); + } + } + @Override public void onHelp() { try (PrintWriter pw = getOutPrintWriter();) { @@ -1321,6 +1355,9 @@ public class VibratorService extends IVibratorService.Stub pw.println(" vibrate duration [description]"); pw.println(" Vibrates for duration milliseconds; ignored when device is on DND "); pw.println(" (Do Not Disturb) mode."); + pw.println(" prebaked effect-id [description]"); + pw.println(" Vibrates with prebaked effect; ignored when device is on DND "); + pw.println(" (Do Not Disturb) mode."); pw.println(""); } } diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 9a47553bf446..ede13ef66ac4 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -873,6 +873,52 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> return null; } + ActivityRecord topRunningActivity() { + return topRunningActivity(false /* considerKeyguardState */); + } + + /** + * Returns the top running activity in the focused stack. In the case the focused stack has no + * such activity, the next focusable stack on this display is returned. + * + * @param considerKeyguardState Indicates whether the locked state should be considered. if + * {@code true} and the keyguard is locked, only activities that + * can be shown on top of the keyguard will be considered. + * @return The top running activity. {@code null} if none is available. + */ + ActivityRecord topRunningActivity(boolean considerKeyguardState) { + ActivityRecord topRunning = null; + final ActivityStack focusedStack = getFocusedStack(); + if (focusedStack != null) { + topRunning = focusedStack.topRunningActivityLocked(); + } + + // Look in other focusable stacks. + if (topRunning == null) { + for (int i = mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = mStacks.get(i); + // Only consider focusable stacks other than the current focused one. + if (stack == focusedStack || !stack.isFocusable()) { + continue; + } + topRunning = stack.topRunningActivityLocked(); + if (topRunning != null) { + break; + } + } + } + + // This activity can be considered the top running activity if we are not considering + // the locked state, the keyguard isn't locked, or we can show when locked. + if (topRunning != null && considerKeyguardState + && mSupervisor.getKeyguardController().isKeyguardLocked() + && !topRunning.canShowWhenLocked()) { + return null; + } + + return topRunning; + } + int getIndexOf(ActivityStack stack) { return mStacks.indexOf(stack); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6f043ecee27a..d56b523f07aa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2106,24 +2106,38 @@ public class ActivityManagerService extends IActivityManager.Stub @VisibleForTesting public ActivityManagerService(Injector injector) { + this(injector, null /* handlerThread */); + } + + /** + * Provides the basic functionality for activity task related tests when a handler thread is + * given to initialize the dependency members. + */ + @VisibleForTesting + ActivityManagerService(Injector injector, ServiceThread handlerThread) { + final boolean hasHandlerThread = handlerThread != null; mInjector = injector; mContext = mInjector.getContext(); mUiContext = null; mAppErrors = null; - mAppOpsService = mInjector.getAppOpsService(null, null); + mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */); mBatteryStatsService = null; - mConstants = null; - mHandler = null; - mHandlerThread = null; - mIntentFirewall = null; + mHandler = hasHandlerThread ? new MainHandler(handlerThread.getLooper()) : null; + mHandlerThread = handlerThread; + mConstants = hasHandlerThread ? new ActivityManagerConstants(this, mHandler) : null; + mIntentFirewall = hasHandlerThread + ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null; mProcessCpuThread = null; mProcessStats = null; mProviderMap = null; - mServices = null; + // For the usage of {@link ActiveServices#cleanUpServices} that may be invoked from + // {@link ActivityStackSupervisor#cleanUpRemovedTaskLocked}. + mServices = hasHandlerThread ? new ActiveServices(this) : null; mSystemThread = null; - mUiHandler = injector.getUiHandler(null); - mUserController = null; - mPendingIntentController = null; + mUiHandler = injector.getUiHandler(null /* service */); + mUserController = hasHandlerThread ? new UserController(this) : null; + mPendingIntentController = hasHandlerThread + ? new PendingIntentController(handlerThread.getLooper(), mUserController) : null; mProcStartHandlerThread = null; mProcStartHandler = null; mHiddenApiBlacklist = null; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 12ed726eca77..026c5cc3017d 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3877,8 +3877,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // The activity that we are finishing may be over the lock screen. In this case, we do not // want to consider activities that cannot be shown on the lock screen as running and should // proceed with finishing the activity if there is no valid next top running activity. - final ActivityRecord next = mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */); + final ActivityDisplay display = getDisplay(); + final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */); if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible) && next != null && !next.nowVisible) { @@ -3902,23 +3902,25 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r); r.setState(FINISHING, "finishCurrentActivityLocked"); - final boolean finishingActivityInNonFocusedStack - = r.getStack() != mStackSupervisor.getTopDisplayFocusedStack() - && prevState == PAUSED && mode == FINISH_AFTER_VISIBLE; + final boolean finishingInNonFocusedStackOrNoRunning = mode == FINISH_AFTER_VISIBLE + && prevState == PAUSED && (r.getStack() != display.getFocusedStack() + || (next == null && display.topRunningActivity() == null)); if (mode == FINISH_IMMEDIATELY || (prevState == PAUSED && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode())) - || finishingActivityInNonFocusedStack + || finishingInNonFocusedStackOrNoRunning || prevState == STOPPING || prevState == STOPPED || prevState == ActivityState.INITIALIZING) { r.makeFinishingLocked(); boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason); - if (finishingActivityInNonFocusedStack) { + if (finishingInNonFocusedStackOrNoRunning) { // Finishing activity that was in paused state and it was in not currently focused - // stack, need to make something visible in its place. + // stack, need to make something visible in its place. Also if the display does not + // have running activity, the configuration may need to be updated for restoring + // original orientation of the display. mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId, false /* markFrozenIfConfigChanged */, true /* deferResume */); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 90e2f5bcd1b4..257a0042b510 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1214,75 +1214,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord topRunningActivityLocked() { - return topRunningActivityLocked(false /* considerKeyguardState */); - } - - /** - * Returns the top running activity in the focused stack. In the case the focused stack has no - * such activity, the next focusable stack on top of a display is returned. - * @param considerKeyguardState Indicates whether the locked state should be considered. if - * {@code true} and the keyguard is locked, only activities that - * can be shown on top of the keyguard will be considered. - * @return The top running activity. {@code null} if none is available. - */ - ActivityRecord topRunningActivityLocked(boolean considerKeyguardState) { - final ActivityStack focusedStack = getTopDisplayFocusedStack(); - ActivityRecord r = focusedStack.topRunningActivityLocked(); - if (r != null && isValidTopRunningActivity(r, considerKeyguardState)) { - return r; - } - - // Look in other non-focused and non-home stacks. for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - - // TODO: We probably want to consider the top fullscreen stack as we could have a pinned - // stack on top. - final ActivityStack topStack = display.getTopStack(); - - // Only consider focusable top stacks other than the current focused one. - if (topStack == null || !topStack.isFocusable() || topStack == focusedStack) { - continue; - } - - final ActivityRecord topActivity = topStack.topRunningActivityLocked(); - - // Skip if no top activity. - if (topActivity == null) { - continue; - } - - - // This activity can be considered the top running activity if we are not - // considering the locked state, the keyguard isn't locked, or we can show when - // locked. - if (isValidTopRunningActivity(topActivity, considerKeyguardState)) { + final ActivityRecord topActivity = mActivityDisplays.get(i).topRunningActivity(); + if (topActivity != null) { return topActivity; } } - return null; } - /** - * Verifies an {@link ActivityRecord} can be the top activity based on keyguard state and - * whether we are considering it. - */ - private boolean isValidTopRunningActivity(ActivityRecord record, - boolean considerKeyguardState) { - if (!considerKeyguardState) { - return true; - } - - final boolean keyguardLocked = getKeyguardController().isKeyguardLocked(); - - if (!keyguardLocked) { - return true; - } - - return record.canShowWhenLocked(); - } - @VisibleForTesting void getRunningTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 8ae5495cfa05..f79d9aa9ba67 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -5864,6 +5864,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void finishHeavyWeightApp() { synchronized (mGlobalLock) { + if (mHeavyWeightProcess != null) { + mHeavyWeightProcess.finishActivities(); + } ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals( mHeavyWeightProcess); } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index fc76b46f5dcf..d57214ea894c 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -109,10 +109,12 @@ import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionInspector; +import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -129,6 +131,9 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; +import com.android.internal.inputmethod.InputMethodDebug; +import com.android.internal.inputmethod.StartInputReason; +import com.android.internal.inputmethod.UnbindReason; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.HandlerCaller; @@ -144,7 +149,6 @@ import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.IInputSessionCallback; import com.android.internal.view.InputBindResult; -import com.android.internal.view.InputMethodClient; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -500,6 +504,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * * @see #mCurFocusedWindow */ + @SoftInputModeFlags int mCurFocusedWindowSoftInputMode; /** @@ -517,6 +522,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags */ + @MissingMethodFlags int mCurInputContextMissingMethods; /** @@ -690,20 +696,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final IBinder mImeToken; @NonNull final String mImeId; - // @InputMethodClient.StartInputReason + @StartInputReason final int mStartInputReason; final boolean mRestarting; @Nullable final IBinder mTargetWindow; @NonNull final EditorInfo mEditorInfo; + @SoftInputModeFlags final int mTargetWindowSoftInputMode; final int mClientBindSequenceNumber; StartInputInfo(@NonNull IBinder imeToken, @NonNull String imeId, - /* @InputMethodClient.StartInputReason */ int startInputReason, boolean restarting, + @StartInputReason int startInputReason, boolean restarting, @Nullable IBinder targetWindow, @NonNull EditorInfo editorInfo, - int targetWindowSoftInputMode, int clientBindSequenceNumber) { + @SoftInputModeFlags int targetWindowSoftInputMode, int clientBindSequenceNumber) { mSequenceNumber = sSequenceNumber.getAndIncrement(); mTimestamp = SystemClock.uptimeMillis(); mWallTime = System.currentTimeMillis(); @@ -771,13 +778,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub String mImeTokenString; @NonNull String mImeId; - /* @InputMethodClient.StartInputReason */ + @StartInputReason int mStartInputReason; boolean mRestarting; @NonNull String mTargetWindowString; @NonNull EditorInfo mEditorInfo; + @SoftInputModeFlags int mTargetWindowSoftInputMode; int mClientBindSequenceNumber; @@ -834,7 +842,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime)) + " (timestamp=" + entry.mTimestamp + ")" + " reason=" - + InputMethodClient.getStartInputReason(entry.mStartInputReason) + + InputMethodDebug.startInputReasonToString(entry.mStartInputReason) + " restarting=" + entry.mRestarting); pw.print(prefix); @@ -846,7 +854,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " clientBindSeq=" + entry.mClientBindSequenceNumber); pw.print(prefix); - pw.println(" softInputMode=" + InputMethodClient.softInputModeToString( + pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString( entry.mTargetWindowSoftInputMode)); pw.print(prefix); @@ -1499,7 +1507,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // TODO: Is it really possible that switchUserLocked() happens before system ready? if (mSystemReady) { hideCurrentInputLocked(0, null); - resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_SWITCH_USER); + resetCurrentMethodAndClient(UnbindReason.SWITCH_USER); buildInputMethodListLocked(initialUserSwitch); if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) { // This is the first time of the user switch and @@ -1729,7 +1737,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * {@link InputMethodManagerService}. * * <p>As a general principle, IPCs from the application process that take - * {@link InputMethodClient} will be rejected without this step.</p> + * {@link IInputMethodClient} will be rejected without this step.</p> * * @param client {@link android.os.Binder} proxy that is associated with the singleton instance * of {@link android.view.inputmethod.InputMethodManager} that runs on the client @@ -1808,8 +1816,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - void unbindCurrentClientLocked( - /* @InputMethodClient.UnbindReason */ final int unbindClientReason) { + void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) { if (mCurClient != null) { if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client=" + mCurClient.client.asBinder()); @@ -1855,8 +1862,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") @NonNull - InputBindResult attachNewInputLocked( - /* @InputMethodClient.StartInputReason */ final int startInputReason, boolean initial) { + InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) { if (!mBoundToMethod) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( MSG_BIND_INPUT, mCurMethod, mCurClient.binding)); @@ -1886,9 +1892,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") @NonNull InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext, - /* @InputConnectionInspector.missingMethods */ final int missingMethods, - @NonNull EditorInfo attribute, int controlFlags, - /* @InputMethodClient.StartInputReason */ final int startInputReason) { + @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute, int controlFlags, + @StartInputReason int startInputReason) { // If no method is currently selected, do nothing. if (mCurMethodId == null) { return InputBindResult.NO_IME; @@ -1921,7 +1926,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurClientInKeyguard = isKeyguardLocked(); // If the client is changing, we need to switch over to the new // one. - unbindCurrentClientLocked(InputMethodClient.UNBIND_REASON_SWITCH_CLIENT); + unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT); if (DEBUG) Slog.v(TAG, "switching to client: client=" + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard); @@ -2046,7 +2051,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurClient.curSession = new SessionState(mCurClient, method, session, channel); InputBindResult res = attachNewInputLocked( - InputMethodClient.START_INPUT_REASON_SESSION_CREATED_BY_IME, true); + StartInputReason.SESSION_CREATED_BY_IME, true); if (res.method != null) { executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO( MSG_BIND_CLIENT, mCurClient.client, res)); @@ -2088,8 +2093,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub clearCurMethodLocked(); } - void resetCurrentMethodAndClient( - /* @InputMethodClient.UnbindReason */ final int unbindClientReason) { + void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) { mCurMethodId = null; unbindCurrentMethodLocked(); unbindCurrentClientLocked(unbindClientReason); @@ -2166,7 +2170,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mLastBindTime = SystemClock.uptimeMillis(); mShowRequested = mInputShown; mInputShown = false; - unbindCurrentClientLocked(InputMethodClient.UNBIND_REASON_DISCONNECT_IME); + unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); } } } @@ -2477,12 +2481,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id)); } catch (IllegalArgumentException e) { Slog.w(TAG, "Unknown input method from prefs: " + id, e); - resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_SWITCH_IME_FAILED); + resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED); } mShortcutInputMethodsAndSubtypes.clear(); } else { // There is no longer an input method set, so stop any current one. - resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_NO_IME); + resetCurrentMethodAndClient(UnbindReason.NO_IME); } // Here is not the perfect place to reset the switching controller. Ideally // mSwitchingController and mSettings should be able to share the same state. @@ -2560,7 +2564,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub intent.putExtra("input_method_id", id); mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); } - unbindCurrentClientLocked(InputMethodClient.UNBIND_REASON_SWITCH_IME); + unbindCurrentClientLocked(UnbindReason.SWITCH_IME); } finally { Binder.restoreCallingIdentity(ident); } @@ -2734,11 +2738,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull @Override public InputBindResult startInputOrWindowGainedFocus( - /* @InputMethodClient.StartInputReason */ final int startInputReason, - IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode, - int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext, - /* @InputConnectionInspector.missingMethods */ final int missingMethods, - int unverifiedTargetSdkVersion) { + @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken, + int controlFlags, @SoftInputModeFlags int softInputMode, int windowFlags, + @Nullable EditorInfo attribute, IInputContext inputContext, + @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) { if (windowToken == null) { Slog.e(TAG, "windowToken cannot be null."); return InputBindResult.NULL; @@ -2749,7 +2752,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (result == null) { // This must never happen, but just in case. Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason=" - + InputMethodClient.getStartInputReason(startInputReason) + + InputMethodDebug.startInputReasonToString(startInputReason) + " windowFlags=#" + Integer.toHexString(windowFlags) + " editorInfo=" + attribute); return InputBindResult.NULL; @@ -2759,12 +2762,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull private InputBindResult startInputOrWindowGainedFocusInternal( - /* @InputMethodClient.StartInputReason */ final int startInputReason, - IInputMethodClient client, @NonNull IBinder windowToken, int controlFlags, - /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode, + @StartInputReason int startInputReason, IInputMethodClient client, + @NonNull IBinder windowToken, int controlFlags, @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute, IInputContext inputContext, - /* @InputConnectionInspector.missingMethods */ final int missingMethods, - int unverifiedTargetSdkVersion) { + @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) { // Needs to check the validity before clearing calling identity final boolean calledFromValidUser = calledFromValidUser(); InputBindResult res = null; @@ -2774,14 +2775,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mWindowManagerInternal.getDisplayIdForWindow(windowToken); synchronized (mMethodMap) { if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason=" - + InputMethodClient.getStartInputReason(startInputReason) + + InputMethodDebug.startInputReasonToString(startInputReason) + " client=" + client.asBinder() + " inputContext=" + inputContext + " missingMethods=" + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods) + " attribute=" + attribute + " controlFlags=#" + Integer.toHexString(controlFlags) - + " softInputMode=" + InputMethodClient.softInputModeToString(softInputMode) + + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode) + " windowFlags=#" + Integer.toHexString(windowFlags) + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion); @@ -4579,7 +4580,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq); p.println(" mCurFocusedWindow=" + mCurFocusedWindow + " softInputMode=" + - InputMethodClient.softInputModeToString(mCurFocusedWindowSoftInputMode) + InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode) + " client=" + mCurFocusedWindowClient); focusedWindowClient = mCurFocusedWindowClient; p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 0c66c5b22d76..6989c334d876 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -55,6 +55,8 @@ import java.util.function.Predicate; * Each app can have a different default networks or different connectivity * status due to user-requested network policies, so we need to check * constraints on a per-UID basis. + * + * Test: atest com.android.server.job.controllers.ConnectivityControllerTest */ public final class ConnectivityController extends StateController implements ConnectivityManager.OnNetworkActiveListener { @@ -65,8 +67,9 @@ public final class ConnectivityController extends StateController implements private final ConnectivityManager mConnManager; private final NetworkPolicyManager mNetPolicyManager; + /** List of tracked jobs keyed by source UID. */ @GuardedBy("mLock") - private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>(); + private final SparseArray<ArraySet<JobStatus>> mTrackedJobs = new SparseArray<>(); public ConnectivityController(JobSchedulerService service) { super(service); @@ -87,7 +90,12 @@ public final class ConnectivityController extends StateController implements public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { if (jobStatus.hasConnectivityConstraint()) { updateConstraintsSatisfied(jobStatus); - mTrackedJobs.add(jobStatus); + ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUid()); + if (jobs == null) { + jobs = new ArraySet<>(); + mTrackedJobs.put(jobStatus.getSourceUid(), jobs); + } + jobs.add(jobStatus); jobStatus.setTrackingController(JobStatus.TRACKING_CONNECTIVITY); } } @@ -97,7 +105,10 @@ public final class ConnectivityController extends StateController implements public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { if (jobStatus.clearTrackingController(JobStatus.TRACKING_CONNECTIVITY)) { - mTrackedJobs.remove(jobStatus); + ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUid()); + if (jobs != null) { + jobs.remove(jobStatus); + } } } @@ -235,47 +246,26 @@ public final class ConnectivityController extends StateController implements /** * Update any jobs tracked by this controller that match given filters. * - * @param filterUid only update jobs belonging to this UID, or {@code -1} to - * update all tracked jobs. + * @param filterUid only update jobs belonging to this UID, or {@code -1} to + * update all tracked jobs. * @param filterNetwork only update jobs that would use this - * {@link Network}, or {@code null} to update all tracked jobs. + * {@link Network}, or {@code null} to update all tracked jobs. */ private void updateTrackedJobs(int filterUid, Network filterNetwork) { synchronized (mLock) { // Since this is a really hot codepath, temporarily cache any // answers that we get from ConnectivityManager. - final SparseArray<Network> uidToNetwork = new SparseArray<>(); final SparseArray<NetworkCapabilities> networkToCapabilities = new SparseArray<>(); boolean changed = false; - for (int i = mTrackedJobs.size() - 1; i >= 0; i--) { - final JobStatus js = mTrackedJobs.valueAt(i); - final int uid = js.getSourceUid(); - - final boolean uidMatch = (filterUid == -1 || filterUid == uid); - if (uidMatch) { - Network network = uidToNetwork.get(uid); - if (network == null) { - network = mConnManager.getActiveNetworkForUid(uid); - uidToNetwork.put(uid, network); - } - - // Update either when we have a network match, or when the - // job hasn't yet been evaluated against the currently - // active network; typically when we just lost a network. - final boolean networkMatch = (filterNetwork == null - || Objects.equals(filterNetwork, network)); - final boolean forceUpdate = !Objects.equals(js.network, network); - if (networkMatch || forceUpdate) { - final int netId = network != null ? network.netId : -1; - NetworkCapabilities capabilities = networkToCapabilities.get(netId); - if (capabilities == null) { - capabilities = mConnManager.getNetworkCapabilities(network); - networkToCapabilities.put(netId, capabilities); - } - changed |= updateConstraintsSatisfied(js, network, capabilities); - } + if (filterUid == -1) { + for (int i = mTrackedJobs.size() - 1; i >= 0; i--) { + changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), + filterNetwork, networkToCapabilities); } + } else { + changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), + filterNetwork, networkToCapabilities); } if (changed) { mStateChangedListener.onControllerStateChanged(); @@ -283,6 +273,36 @@ public final class ConnectivityController extends StateController implements } } + private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork, + SparseArray<NetworkCapabilities> networkToCapabilities) { + if (jobs == null || jobs.size() == 0) { + return false; + } + + final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid()); + final int netId = network != null ? network.netId : -1; + NetworkCapabilities capabilities = networkToCapabilities.get(netId); + if (capabilities == null) { + capabilities = mConnManager.getNetworkCapabilities(network); + networkToCapabilities.put(netId, capabilities); + } + final boolean networkMatch = (filterNetwork == null + || Objects.equals(filterNetwork, network)); + + boolean changed = false; + for (int i = jobs.size() - 1; i >= 0; i--) { + final JobStatus js = jobs.valueAt(i); + + // Update either when we have a network match, or when the + // job hasn't yet been evaluated against the currently + // active network; typically when we just lost a network. + if (networkMatch || !Objects.equals(js.network, network)) { + changed |= updateConstraintsSatisfied(js, network, capabilities); + } + } + return changed; + } + /** * We know the network has just come up. We want to run any jobs that are ready. */ @@ -290,12 +310,15 @@ public final class ConnectivityController extends StateController implements public void onNetworkActive() { synchronized (mLock) { for (int i = mTrackedJobs.size()-1; i >= 0; i--) { - final JobStatus js = mTrackedJobs.valueAt(i); - if (js.isReady()) { - if (DEBUG) { - Slog.d(TAG, "Running " + js + " due to network activity."); + final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i); + for (int j = jobs.size() - 1; j >= 0; j--) { + final JobStatus js = jobs.valueAt(j); + if (js.isReady()) { + if (DEBUG) { + Slog.d(TAG, "Running " + js + " due to network activity."); + } + mStateChangedListener.onRunJobNow(js); } - mStateChangedListener.onRunJobNow(js); } } } @@ -334,8 +357,12 @@ public final class ConnectivityController extends StateController implements public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { for (int i = 0; i < mTrackedJobs.size(); i++) { - final JobStatus js = mTrackedJobs.valueAt(i); - if (predicate.test(js)) { + final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i); + for (int j = 0; j < jobs.size(); j++) { + final JobStatus js = jobs.valueAt(j); + if (!predicate.test(js)) { + continue; + } pw.print("#"); js.printUniqueId(pw); pw.print(" from "); @@ -355,20 +382,26 @@ public final class ConnectivityController extends StateController implements final long mToken = proto.start(StateControllerProto.CONNECTIVITY); for (int i = 0; i < mTrackedJobs.size(); i++) { - final JobStatus js = mTrackedJobs.valueAt(i); - if (!predicate.test(js)) { - continue; - } - final long jsToken = proto.start(StateControllerProto.ConnectivityController.TRACKED_JOBS); - js.writeToShortProto(proto, StateControllerProto.ConnectivityController.TrackedJob.INFO); - proto.write(StateControllerProto.ConnectivityController.TrackedJob.SOURCE_UID, - js.getSourceUid()); - NetworkRequest rn = js.getJob().getRequiredNetwork(); - if (rn != null) { - rn.writeToProto(proto, - StateControllerProto.ConnectivityController.TrackedJob.REQUIRED_NETWORK); + final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i); + for (int j = 0; j < jobs.size(); j++) { + final JobStatus js = jobs.valueAt(j); + if (!predicate.test(js)) { + continue; + } + final long jsToken = proto.start( + StateControllerProto.ConnectivityController.TRACKED_JOBS); + js.writeToShortProto(proto, + StateControllerProto.ConnectivityController.TrackedJob.INFO); + proto.write(StateControllerProto.ConnectivityController.TrackedJob.SOURCE_UID, + js.getSourceUid()); + NetworkRequest rn = js.getJob().getRequiredNetwork(); + if (rn != null) { + rn.writeToProto(proto, + StateControllerProto.ConnectivityController.TrackedJob + .REQUIRED_NETWORK); + } + proto.end(jsToken); } - proto.end(jsToken); } proto.end(mToken); diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 3f8941dfb21b..4ece538d6d31 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -57,6 +57,8 @@ import java.util.function.Predicate; * This isn't strictly necessary because each controller is only interested in a specific field, * and the receivers that are listening for global state change will all run on the main looper, * but we don't enforce that so this is safer. + * + * Test: atest com.android.server.job.controllers.JobStatusTest * @hide */ public final class JobStatus { @@ -154,7 +156,9 @@ public final class JobStatus { // Constraints. final int requiredConstraints; + private final int mRequiredConstraintsOfInterest; int satisfiedConstraints = 0; + private int mSatisfiedConstraintsOfInterest = 0; // Set to true if doze constraint was satisfied due to app being whitelisted. public boolean dozeWhitelisted; @@ -265,6 +269,28 @@ public final class JobStatus { private long totalNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN; + /////// Booleans that track if a job is ready to run. They should be updated whenever dependent + /////// states change. + + /** + * The deadline for the job has passed. This is only good for non-periodic jobs. A periodic job + * should only run if its constraints are satisfied. + * Computed as: NOT periodic AND has deadline constraint AND deadline constraint satisfied. + */ + private boolean mReadyDeadlineSatisfied; + + /** + * The device isn't Dozing or this job will be in the foreground. This implicit constraint must + * be satisfied. + */ + private boolean mReadyNotDozing; + + /** + * The job is not restricted from running in the background (due to Battery Saver). This + * implicit constraint must be satisfied. + */ + private boolean mReadyNotRestrictedInBg; + /** Provide a handle to the service that this job will be run on. */ public int getServiceToken() { return callingUid; @@ -349,6 +375,8 @@ public final class JobStatus { requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; } this.requiredConstraints = requiredConstraints; + mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST; + mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; mLastSuccessfulRunTime = lastSuccessfulRunTime; mLastFailedRunTime = lastFailedRunTime; @@ -865,7 +893,12 @@ public final class JobStatus { } boolean setDeadlineConstraintSatisfied(boolean state) { - return setConstraintSatisfied(CONSTRAINT_DEADLINE, state); + if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) { + // The constraint was changed. Update the ready flag. + mReadyDeadlineSatisfied = !job.isPeriodic() && hasDeadlineConstraint() && state; + return true; + } + return false; } boolean setIdleConstraintSatisfied(boolean state) { @@ -882,11 +915,21 @@ public final class JobStatus { boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) { dozeWhitelisted = whitelisted; - return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state); + if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) { + // The constraint was changed. Update the ready flag. + mReadyNotDozing = state || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; + return true; + } + return false; } boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) { - return setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state); + if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) { + // The constraint was changed. Update the ready flag. + mReadyNotRestrictedInBg = state; + return true; + } + return false; } boolean setUidActive(final boolean newActiveState) { @@ -903,6 +946,7 @@ public final class JobStatus { return false; } satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0); + mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; return true; } @@ -933,24 +977,15 @@ public final class JobStatus { /** * @return Whether or not this job is ready to run, based on its requirements. This is true if * the constraints are satisfied <strong>or</strong> the deadline on the job has expired. - * TODO: This function is called a *lot*. We should probably just have it check an - * already-computed boolean, which we updated whenever we see one of the states it depends - * on here change. */ public boolean isReady() { // Deadline constraint trumps other constraints (except for periodic jobs where deadline // is an implementation detail. A periodic job should only run if its constraints are // satisfied). - // AppNotIdle implicit constraint must be satisfied // DeviceNotDozing implicit constraint must be satisfied // NotRestrictedInBackground implicit constraint must be satisfied - final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint() - && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0); - final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0 - || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; - final boolean notRestrictedInBg = - (satisfiedConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0; - return (isConstraintsSatisfied() || deadlineSatisfied) && notDozing && notRestrictedInBg; + return mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied + || isConstraintsSatisfied()); } static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW @@ -971,15 +1006,13 @@ public final class JobStatus { return true; } - final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST; - - int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; + int sat = mSatisfiedConstraintsOfInterest; if (overrideState == OVERRIDE_SOFT) { // override: pretend all 'soft' requirements are satisfied sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS); } - return (sat & req) == req; + return (sat & mRequiredConstraintsOfInterest) == mRequiredConstraintsOfInterest; } public boolean matches(int uid, int jobId) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 506cc441c868..93b83ae72cca 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -719,8 +719,7 @@ public class NotificationManagerService extends SystemService { return; } final long now = System.currentTimeMillis(); - MetricsLogger.action(r.getLogMaker(now) - .setCategory(MetricsEvent.NOTIFICATION_ITEM) + MetricsLogger.action(r.getItemLogMaker() .setType(MetricsEvent.TYPE_ACTION) .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); @@ -865,8 +864,7 @@ public class NotificationManagerService extends SystemService { r.stats.onExpansionChanged(userAction, expanded); final long now = System.currentTimeMillis(); if (userAction) { - MetricsLogger.action(r.getLogMaker(now) - .setCategory(MetricsEvent.NOTIFICATION_ITEM) + MetricsLogger.action(r.getItemLogMaker() .setType(expanded ? MetricsEvent.TYPE_DETAIL : MetricsEvent.TYPE_COLLAPSE)); } @@ -3624,7 +3622,7 @@ public class NotificationManagerService extends SystemService { INotificationListener token, String pkg, UserHandle user, NotificationChannelGroup group) throws RemoteException { Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, false); createNotificationChannelGroup( pkg, getUidForPackageAndUser(pkg, user), group, false, true); savePolicyFile(); @@ -3637,7 +3635,7 @@ public class NotificationManagerService extends SystemService { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, false); updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); } @@ -3646,7 +3644,7 @@ public class NotificationManagerService extends SystemService { INotificationListener token, String pkg, UserHandle user) throws RemoteException { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, true); return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), false /* includeDeleted */); @@ -3658,7 +3656,7 @@ public class NotificationManagerService extends SystemService { INotificationListener token, String pkg, UserHandle user) throws RemoteException { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, true); List<NotificationChannelGroup> groups = new ArrayList<>(); groups.addAll(mPreferencesHelper.getNotificationChannelGroups( @@ -3666,13 +3664,18 @@ public class NotificationManagerService extends SystemService { return new ParceledListSlice<>(groups); } - private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { + private void verifyPrivilegedListener(INotificationListener token, UserHandle user, + boolean assistantAllowed) { ManagedServiceInfo info; synchronized (mNotificationLock) { info = mListeners.checkServiceTokenLocked(token); } if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); + synchronized (mNotificationLock) { + if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) { + throw new SecurityException(info + " does not have access"); + } + } } if (!info.enabledAndUserMatches(user.getIdentifier())) { throw new SecurityException(info + " does not have access"); @@ -5842,8 +5845,7 @@ public class NotificationManagerService extends SystemService { mArchive.record(r.sbn); final long now = System.currentTimeMillis(); - final LogMaker logMaker = r.getLogMaker(now) - .setCategory(MetricsEvent.NOTIFICATION_ITEM) + final LogMaker logMaker = r.getItemLogMaker() .setType(MetricsEvent.TYPE_DISMISS) .setSubtype(reason); if (rank != -1 && count != -1) { diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 65ec5808a0dd..e9f2718fe2b3 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -611,6 +611,7 @@ public final class NotificationRecord { } public void applyAdjustments() { + long now = System.currentTimeMillis(); synchronized (mAdjustments) { for (Adjustment adjustment: mAdjustments) { Bundle signals = adjustment.getSignals(); @@ -618,17 +619,25 @@ public final class NotificationRecord { final ArrayList<String> people = adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE); setPeopleOverride(people); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_PEOPLE, people.size())); } if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) { final ArrayList<SnoozeCriterion> snoozeCriterionList = adjustment.getSignals().getParcelableArrayList( Adjustment.KEY_SNOOZE_CRITERIA); setSnoozeCriteria(snoozeCriterionList); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SNOOZE_CRITERIA, + snoozeCriterionList.size())); } if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) { final String groupOverrideKey = adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY); setOverrideGroupKey(groupOverrideKey); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_GROUP_KEY, + groupOverrideKey)); } if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) { // Only allow user sentiment update from assistant if user hasn't already @@ -637,19 +646,31 @@ public final class NotificationRecord { && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) { setUserSentiment(adjustment.getSignals().getInt( Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL)); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_USER_SENTIMENT, + getUserSentiment())); } } if (signals.containsKey(Adjustment.KEY_SMART_ACTIONS)) { setSmartActions(signals.getParcelableArrayList(Adjustment.KEY_SMART_ACTIONS)); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_ACTIONS, + getSmartActions().size())); } if (signals.containsKey(Adjustment.KEY_SMART_REPLIES)) { setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES)); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES, + getSmartReplies().size())); } if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) { int importance = signals.getInt(Adjustment.KEY_IMPORTANCE); importance = Math.max(IMPORTANCE_UNSPECIFIED, importance); importance = Math.min(IMPORTANCE_HIGH, importance); setAssistantImportance(importance); + MetricsLogger.action(getAdjustmentLogMaker() + .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_IMPORTANCE, + importance)); } } } @@ -732,10 +753,10 @@ public final class NotificationRecord { protected void calculateImportance() { mImportance = calculateInitialImportance(); mImportanceExplanation = "app"; - if (getChannel().isImportanceLocked()) { + if (getChannel().hasUserSetImportance()) { mImportanceExplanation = "user"; } - if (!getChannel().isImportanceLocked() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) { + if (!getChannel().hasUserSetImportance() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) { mImportance = mAssistantImportance; mImportanceExplanation = "asst"; } @@ -1203,6 +1224,16 @@ public final class NotificationRecord { return getLogMaker(System.currentTimeMillis()); } + public LogMaker getItemLogMaker() { + return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM); + } + + public LogMaker getAdjustmentLogMaker() { + return getLogMaker() + .setCategory(MetricsEvent.NOTIFICATION_ITEM) + .setType(MetricsEvent.NOTIFICATION_ASSISTANT_ADJUSTMENT); + } + @VisibleForTesting static final class Light { public final int color; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 760f1559c845..44b80c138346 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1212,27 +1212,89 @@ public class ZenModeHelper { } private final class Metrics extends Callback { - private static final String COUNTER_PREFIX = "dnd_mode_"; + private static final String COUNTER_MODE_PREFIX = "dnd_mode_"; + private static final String COUNTER_TYPE_PREFIX = "dnd_type_"; + private static final int DND_OFF = 0; + private static final int DND_ON_MANUAL = 1; + private static final int DND_ON_AUTOMATIC = 2; + private static final String COUNTER_RULE = "dnd_rule_count"; private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000; + // Total silence, alarms only, priority only private int mPreviousZenMode = -1; - private long mBeginningMs = 0L; + private long mModeLogTimeMs = 0L; + + private int mNumZenRules = -1; + private long mRuleCountLogTime = 0L; + + // automatic (1) vs manual (0) vs dnd off (2) + private int mPreviousZenType = -1; + private long mTypeLogTimeMs = 0L; @Override void onZenModeChanged() { emit(); } + @Override + void onConfigChanged() { + emit(); + } + private void emit() { mHandler.postMetricsTimer(); + emitZenMode(); + emitRules(); + emitDndType(); + } + + private void emitZenMode() { final long now = SystemClock.elapsedRealtime(); - final long since = (now - mBeginningMs); + final long since = (now - mModeLogTimeMs); if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) { if (mPreviousZenMode != -1) { - MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since); + MetricsLogger.count( + mContext, COUNTER_MODE_PREFIX + mPreviousZenMode, (int) since); } mPreviousZenMode = mZenMode; - mBeginningMs = now; + mModeLogTimeMs = now; + } + } + + private void emitRules() { + final long now = SystemClock.elapsedRealtime(); + final long since = (now - mRuleCountLogTime); + synchronized (mConfig) { + int numZenRules = mConfig.automaticRules.size(); + if (mNumZenRules != numZenRules + || since > MINIMUM_LOG_PERIOD_MS) { + if (mNumZenRules != -1) { + MetricsLogger.count(mContext, COUNTER_RULE, + numZenRules - mNumZenRules); + } + mNumZenRules = numZenRules; + + mRuleCountLogTime = since; + } + } + } + + private void emitDndType() { + final long now = SystemClock.elapsedRealtime(); + final long since = (now - mTypeLogTimeMs); + synchronized (mConfig) { + boolean dndOn = mZenMode != Global.ZEN_MODE_OFF; + int zenType = !dndOn ? DND_OFF + : (mConfig.manualRule != null) ? DND_ON_MANUAL : DND_ON_AUTOMATIC; + if (zenType != mPreviousZenType + || since > MINIMUM_LOG_PERIOD_MS) { + if (mPreviousZenType != -1) { + MetricsLogger.count( + mContext, COUNTER_TYPE_PREFIX + mPreviousZenType, (int) since); + } + mTypeLogTimeMs = now; + mPreviousZenType = zenType; + } } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1180af87ae34..9399ebf5b413 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9539,7 +9539,7 @@ public class PackageManagerService extends IPackageManager.Stub } } } - if (deleteSandboxData) { + if (deleteSandboxData && getStorageManagerInternal() != null) { getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId); } } catch (PackageManagerException e) { diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index be24c7125969..5569822300b9 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -243,7 +243,7 @@ public class BatterySaverController implements BatterySaverPolicyListener { } /** - * Called by {@link PowerManagerService} to update the battery saver stete. + * Called by {@link PowerManagerService} to update the battery saver state. */ public void enableBatterySaver(boolean enable, int reason) { synchronized (mLock) { @@ -290,8 +290,8 @@ public class BatterySaverController implements BatterySaverPolicyListener { * This method is called only in the following cases: * - When battery saver becomes activated. * - When battery saver becomes deactivated. - * - When battery saver is on the interactive state changes. - * - When battery saver is on the battery saver policy changes. + * - When battery saver is on and the interactive state changes. + * - When battery saver is on and the battery saver policy changes. */ void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) { final LowPowerModeListener[] listeners; diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 6db7e4f1a800..93870e73ecab 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -88,7 +88,6 @@ import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; import com.android.internal.os.LooperStats; import com.android.internal.os.PowerProfile; -import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.StoragedUidIoStatsReader; import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; @@ -175,6 +174,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); private IWifiManager mWifiManager = null; private TelephonyManager mTelephony = null; + private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath()); + private final StatFs mStatFsSystem = + new StatFs(Environment.getRootDirectory().getAbsolutePath()); + private final StatFs mStatFsTemp = + new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); @GuardedBy("sStatsdLock") private final HashSet<Long> mDeathTimeMillis = new HashSet<>(); @GuardedBy("sStatsdLock") @@ -195,8 +199,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static IThermalService sThermalService; private File mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_companion"); - @GuardedBy("this") - ProcessCpuTracker mProcessCpuTracker = null; public StatsCompanionService(Context context) { super(); @@ -770,7 +772,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullBluetoothBytesTransfer( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = fetchBluetoothData(); + BluetoothActivityEnergyInfo info = pullBluetoothData(); if (info.getUidTraffic() != null) { for (UidTraffic traffic : info.getUidTraffic()) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, @@ -882,12 +884,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { long token = Binder.clearCallingIdentity(); - synchronized (this) { - if (mWifiManager == null) { - mWifiManager = - IWifiManager.Stub.asInterface( - ServiceManager.getService(Context.WIFI_SERVICE)); - } + if (mWifiManager == null) { + mWifiManager = + IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE)); } if (mWifiManager != null) { try { @@ -917,10 +916,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { long token = Binder.clearCallingIdentity(); - synchronized (this) { - if (mTelephony == null) { - mTelephony = TelephonyManager.from(mContext); - } + if (mTelephony == null) { + mTelephony = TelephonyManager.from(mContext); } if (mTelephony != null) { SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); @@ -944,7 +941,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullBluetoothActivityInfo( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = fetchBluetoothData(); + BluetoothActivityEnergyInfo info = pullBluetoothData(); StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeLong(info.getTimeStamp()); e.writeInt(info.getBluetoothStackState()); @@ -955,7 +952,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } - private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { + private synchronized BluetoothActivityEnergyInfo pullBluetoothData() { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( @@ -1326,35 +1323,30 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullProcessStats(int section, int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { - synchronized (this) { - try { - long lastHighWaterMark = readProcStatsHighWaterMark(section); - List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); - long highWaterMark = mProcessStats.getCommittedStats( - lastHighWaterMark, section, true, statsFiles); - if (statsFiles.size() != 1) { - return; - } - InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream( - statsFiles.get(0)); - int[] len = new int[1]; - byte[] stats = readFully(stream, len); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeStorage(Arrays.copyOf(stats, len[0])); - pulledData.add(e); - new File(mBaseDir.getAbsolutePath() + "/" + section + "_" - + lastHighWaterMark).delete(); - new File( - mBaseDir.getAbsolutePath() + "/" + section + "_" - + highWaterMark).createNewFile(); - } catch (IOException e) { - Log.e(TAG, "Getting procstats failed: ", e); - } catch (RemoteException e) { - Log.e(TAG, "Getting procstats failed: ", e); - } catch (SecurityException e) { - Log.e(TAG, "Getting procstats failed: ", e); + try { + long lastHighWaterMark = readProcStatsHighWaterMark(section); + List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); + long highWaterMark = mProcessStats.getCommittedStats( + lastHighWaterMark, section, true, statsFiles); + if (statsFiles.size() != 1) { + return; } + InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0)); + int[] len = new int[1]; + byte[] stats = readFully(stream, len); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeStorage(Arrays.copyOf(stats, len[0])); + pulledData.add(e); + new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark).delete(); + new File( + mBaseDir.getAbsolutePath() + "/" + section + "_" + + highWaterMark).createNewFile(); + } catch (IOException e) { + Log.e(TAG, "Getting procstats failed: ", e); + } catch (RemoteException e) { + Log.e(TAG, "Getting procstats failed: ", e); + } catch (SecurityException e) { + Log.e(TAG, "Getting procstats failed: ", e); } } @@ -1423,34 +1415,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { }); } - private void pullProcessCpuTime(int tagId, long elapsedNanos, final long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - synchronized (this) { - if (mProcessCpuTracker == null) { - mProcessCpuTracker = new ProcessCpuTracker(false); - mProcessCpuTracker.init(); - } - mProcessCpuTracker.update(); - for (int i = 0; i < mProcessCpuTracker.countStats(); i++) { - ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeInt(st.uid); - e.writeString(st.name); - e.writeLong(st.base_utime); - e.writeLong(st.base_stime); - pulledData.add(e); - } - } - } - /** * Pulls various data. */ @Override // Binder call public StatsLogEventWrapper[] pullData(int tagId) { enforceCallingPermission(); - if (DEBUG) { Slog.d(TAG, "Pulling " + tagId); } @@ -1563,8 +1533,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } case StatsLog.PROC_STATS: { - pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, - ret); + pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, ret); break; } case StatsLog.PROC_STATS_PKG_PROC: { @@ -1580,10 +1549,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret); break; } - case StatsLog.PROCESS_CPU_TIME: { - pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret); - break; - } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 26ea152761fb..b88165ef0f24 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -206,6 +206,7 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.StatsLog; import android.util.Xml; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; @@ -9387,6 +9388,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } saveUserRestrictionsLocked(userHandle); } + StatsLog.write(StatsLog.USER_RESTRICTION_CHANGED, key, enabledFromThisOwner); if (SecurityLog.isLoggingEnabled()) { final int eventTag = enabledFromThisOwner ? SecurityLog.TAG_USER_RESTRICTION_ADDED diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index de3d285cd23a..877c8fad3086 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -58,6 +58,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.annotations.GuardedBy; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -67,8 +69,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoSession; -import javax.annotation.concurrent.GuardedBy; - @SmallTest @RunWith(AndroidJUnit4.class) public class AlarmManagerServiceTest { diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index 1752479ade35..b63138edfd21 100644 --- a/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -16,19 +16,27 @@ package com.android.server.job.controllers; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static org.junit.Assert.assertEquals; import android.app.job.JobInfo; import android.content.ComponentName; +import android.content.pm.PackageManagerInternal; import android.os.SystemClock; import androidx.test.runner.AndroidJUnit4; +import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoSession; import java.time.Clock; import java.time.ZoneOffset; @@ -37,8 +45,17 @@ import java.time.ZoneOffset; public class JobStatusTest { private static final double DELTA = 0.00001; + private MockitoSession mMockingSession; + @Before public void setUp() throws Exception { + mMockingSession = mockitoSession() + .initMocks(this) + .mockStatic(LocalServices.class) + .startMocking(); + doReturn(mock(PackageManagerInternal.class)) + .when(() -> LocalServices.getService(PackageManagerInternal.class)); + // Freeze the clocks at this moment in time JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC); @@ -48,6 +65,13 @@ public class JobStatusTest { Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC); } + @After + public void tearDown() { + if (mMockingSession != null) { + mMockingSession.finishMocking(); + } + } + @Test public void testFraction() throws Exception { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java index ea90ffd0792f..0da574239666 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java @@ -20,11 +20,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; import android.platform.test.annotations.Presubmit; @@ -131,4 +134,57 @@ public class ActivityDisplayTests extends ActivityTestsBase { new ActivityBuilder(mService).setTask(fullscreenTask).build(); return fullscreenStack; } + + /** + * Verifies the correct activity is returned when querying the top running activity. + */ + @Test + public void testTopRunningActivity() { + // Create stack to hold focus. + final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + final ActivityStack emptyStack = display.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, true /* onTop */); + + final KeyguardController keyguard = mSupervisor.getKeyguardController(); + final ActivityStack stack = mSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + + // Make sure the top running activity is not affected when keyguard is not locked. + assertTopRunningActivity(activity, display); + + // Check to make sure activity not reported when it cannot show on lock and lock is on. + doReturn(true).when(keyguard).isKeyguardLocked(); + assertEquals(activity, display.topRunningActivity()); + assertNull(display.topRunningActivity(true /* considerKeyguardState */)); + + // Change focus to stack with activity. + stack.moveToFront("focusChangeToTestStack"); + assertEquals(stack, display.getFocusedStack()); + assertEquals(activity, display.topRunningActivity()); + assertNull(display.topRunningActivity(true /* considerKeyguardState */)); + + // Add activity that should be shown on the keyguard. + final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService) + .setCreateTask(true) + .setStack(stack) + .setActivityFlags(FLAG_SHOW_WHEN_LOCKED) + .build(); + + // Ensure the show when locked activity is returned. + assertTopRunningActivity(showWhenLockedActivity, display); + + // Change focus back to empty stack. + emptyStack.moveToFront("focusChangeToEmptyStack"); + assertEquals(emptyStack, display.getFocusedStack()); + // If there is no running activity in focused stack, the running activity in next focusable + // stack should be returned. + assertTopRunningActivity(showWhenLockedActivity, display); + } + + private static void assertTopRunningActivity(ActivityRecord top, ActivityDisplay display) { + assertEquals(top, display.topRunningActivity()); + assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */)); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index cc7a24d5700e..2c993d32c20c 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -25,7 +25,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; -import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; @@ -307,62 +306,6 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { } /** - * Verifies the correct activity is returned when querying the top running activity. - */ - @Test - public void testTopRunningActivity() throws Exception { - // Create stack to hold focus - final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay(); - final ActivityStack emptyStack = display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, true /* onTop */); - - final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(stack).build(); - - // Make sure the top running activity is not affected when keyguard is not locked - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Check to make sure activity not reported when it cannot show on lock and lock is on. - doReturn(true).when(keyguard).isKeyguardLocked(); - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Change focus to stack with activity. - stack.moveToFront("focusChangeToTestStack"); - assertEquals(stack, display.getFocusedStack()); - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Add activity that should be shown on the keyguard. - final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService) - .setCreateTask(true) - .setStack(stack) - .setActivityFlags(FLAG_SHOW_WHEN_LOCKED) - .build(); - - // Ensure the show when locked activity is returned. - assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Change focus back to empty stack - emptyStack.moveToFront("focusChangeToEmptyStack"); - assertEquals(emptyStack, display.getFocusedStack()); - // Looking for running activity only in top and focused stack, so nothing should be returned - // from empty stack. - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - } - - /** * Verify that split-screen primary stack will be chosen if activity is launched that targets * split-screen secondary, but a matching existing instance is found on top of split-screen * primary stack. diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 5fcd2aa35e05..53f67afb629e 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -26,6 +26,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; +import static com.android.server.am.ActivityStack.ActivityState.FINISHING; +import static com.android.server.am.ActivityStack.ActivityState.PAUSED; import static com.android.server.am.ActivityStack.ActivityState.PAUSING; import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; @@ -35,10 +38,14 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.anyInt; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -655,6 +662,39 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test + public void testFinishCurrentActivity() { + // Create 2 activities on a new display. + final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); + final ActivityStack stack1 = createStackForShouldBeVisibleTest(display, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityStack stack2 = createStackForShouldBeVisibleTest(display, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + + // There is still an activity1 in stack1 so the activity2 should be added to finishing list + // that will be destroyed until idle. + final ActivityRecord activity2 = finishCurrentActivity(stack2); + assertEquals(FINISHING, activity2.getState()); + assertTrue(mSupervisor.mFinishingActivities.contains(activity2)); + + // The display becomes empty. Since there is no next activity to be idle, the activity + // should be destroyed immediately with updating configuration to restore original state. + final ActivityRecord activity1 = finishCurrentActivity(stack1); + assertEquals(DESTROYING, activity1.getState()); + verify(mSupervisor).ensureVisibilityAndConfig(eq(null) /* starting */, + eq(display.mDisplayId), anyBoolean(), anyBoolean()); + } + + private ActivityRecord finishCurrentActivity(ActivityStack stack) { + final ActivityRecord activity = stack.topRunningActivityLocked(); + assertNotNull(activity); + activity.setState(PAUSED, "finishCurrentActivity"); + activity.makeFinishingLocked(); + stack.finishCurrentActivityLocked(activity, ActivityStack.FINISH_AFTER_VISIBLE, + false /* oomAdj */, "finishCurrentActivity"); + return activity; + } + + @Test public void testShouldSleepActivities() throws Exception { // When focused activity and keyguard is going away, we should not sleep regardless // of the display state diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 58fe70d7d992..01d51e44146c 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -58,8 +58,9 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; -import android.os.HandlerThread; +import android.os.Handler; import android.os.Looper; +import android.os.Process; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.testing.DexmakerShareClassLoaderRule; @@ -69,7 +70,9 @@ import android.view.DisplayInfo; import androidx.test.InstrumentationRegistry; import com.android.internal.app.IVoiceInteractor; +import com.android.server.AppOpsService; import com.android.server.AttributeCache; +import com.android.server.ServiceThread; import com.android.server.wm.AppWindowContainerController; import com.android.server.wm.PinnedStackWindowController; import com.android.server.wm.RootWindowContainerController; @@ -82,6 +85,7 @@ import org.junit.After; import org.junit.Before; import org.mockito.MockitoAnnotations; +import java.io.File; import java.util.List; /** @@ -97,7 +101,7 @@ public class ActivityTestsBase { new DexmakerShareClassLoaderRule(); private final Context mContext = InstrumentationRegistry.getContext(); - private HandlerThread mHandlerThread; + final TestInjector mTestInjector = new TestInjector(); ActivityTaskManagerService mService; ActivityStackSupervisor mSupervisor; @@ -115,13 +119,12 @@ public class ActivityTestsBase { MockitoAnnotations.initMocks(this); AttributeCache.init(mContext); } - mHandlerThread = new HandlerThread("ActivityTestsBaseThread"); - mHandlerThread.start(); + mTestInjector.setUp(); } @After public void tearDown() { - mHandlerThread.quitSafely(); + mTestInjector.tearDown(); } protected ActivityTaskManagerService createActivityTaskManagerService() { @@ -143,7 +146,7 @@ public class ActivityTestsBase { } ActivityManagerService setupActivityManagerService(TestActivityTaskManagerService atm) { - final TestActivityManagerService am = spy(new TestActivityManagerService(mContext, atm)); + final TestActivityManagerService am = spy(new TestActivityManagerService(mTestInjector)); setupActivityManagerService(am, atm); return am; } @@ -173,6 +176,7 @@ public class ActivityTestsBase { doReturn(mockPackageManager).when(am).getPackageManagerInternalLocked(); doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt()); doNothing().when(am).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt()); + am.mActivityTaskManager = atm; am.mWindowManager = prepareMockWindowManager(); atm.setWindowManager(am.mWindowManager); @@ -192,8 +196,6 @@ public class ActivityTestsBase { // An id appended to the end of the component name to make it unique private static int sCurrentActivityId = 0; - - private final ActivityTaskManagerService mService; private ComponentName mComponent; @@ -487,6 +489,40 @@ public class ActivityTestsBase { } } + private static class TestInjector extends ActivityManagerService.Injector { + private ServiceThread mHandlerThread; + + @Override + public Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Override + public AppOpsService getAppOpsService(File file, Handler handler) { + return null; + } + + @Override + public Handler getUiHandler(ActivityManagerService service) { + return mHandlerThread.getThreadHandler(); + } + + @Override + public boolean isNetworkRestrictedForUid(int uid) { + return false; + } + + void setUp() { + mHandlerThread = new ServiceThread("ActivityTestsThread", + Process.THREAD_PRIORITY_DEFAULT, true /* allowIo */); + mHandlerThread.start(); + } + + void tearDown() { + mHandlerThread.quitSafely(); + } + } + /** * An {@link ActivityManagerService} subclass which provides a test * {@link ActivityStackSupervisor}. @@ -495,8 +531,8 @@ public class ActivityTestsBase { private ActivityManagerInternal mInternal; - TestActivityManagerService(Context context, TestActivityTaskManagerService atm) { - super(context, atm); + TestActivityManagerService(TestInjector testInjector) { + super(testInjector, testInjector.mHandlerThread); mUgmInternal = mock(UriGrantsManagerInternal.class); } diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java index 62c5734561f9..75f7c4c2cdff 100644 --- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java +++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java @@ -45,7 +45,7 @@ import java.util.List; @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class BroadcastRecordTest extends ActivityTestsBase { +public class BroadcastRecordTest { @Test public void testCleanupDisabledPackageReceivers() { diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java index 1276f656f914..27e8c632c1bd 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java @@ -116,8 +116,7 @@ public class RecentTasksTest extends ActivityTestsBase { mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); mService = spy(new MyTestActivityTaskManagerService(mContext)); - final TestActivityManagerService am = - spy(new MyTestActivityManagerService(mContext, mService)); + final TestActivityManagerService am = spy(new MyTestActivityManagerService()); setupActivityManagerService(am, mService); mRecentTasks = (TestRecentTasks) mService.getRecentTasks(); mRecentTasks.loadParametersFromResources(mContext.getResources()); @@ -848,8 +847,8 @@ public class RecentTasksTest extends ActivityTestsBase { } private class MyTestActivityManagerService extends TestActivityManagerService { - MyTestActivityManagerService(Context context, TestActivityTaskManagerService atm) { - super(context, atm); + MyTestActivityManagerService() { + super(mTestInjector); } @Override diff --git a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java index 921cdea2e646..27766d3d8d6c 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java @@ -69,13 +69,11 @@ public class TaskRecordTests extends ActivityTestsBase { private static final String TASK_TAG = "task"; - private ActivityTaskManagerService mService; - @Before public void setUp() throws Exception { super.setUp(); TaskRecord.setTaskRecordFactory(null); - mService = createActivityTaskManagerService(); + setupActivityTaskManagerService(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 869f8fa0c2fa..caaa0bbe6c60 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -43,6 +43,7 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import android.app.usage.AppStandbyInfo; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; @@ -92,6 +93,8 @@ public class AppStandbyControllerTests { private static final int USER_ID = 0; private static final int USER_ID2 = 10; + private static final String PACKAGE_UNKNOWN = "com.example.unknown"; + private static final String ADMIN_PKG = "com.android.admin"; private static final String ADMIN_PKG2 = "com.android.admin2"; private static final String ADMIN_PKG3 = "com.android.admin3"; @@ -106,6 +109,9 @@ public class AppStandbyControllerTests { // Short STABLE_CHARGING_THRESHOLD for testing purposes private static final long STABLE_CHARGING_THRESHOLD = 2000; + /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */ + private static boolean isPackageInstalled = true; + private MyInjector mInjector; private AppStandbyController mController; @@ -183,6 +189,12 @@ public class AppStandbyControllerTests { } @Override + boolean isPackageInstalled(String packageName, int flags, int userId) { + // Should always return true (default value) unless testing for an uninstalled app + return isPackageInstalled; + } + + @Override int[] getRunningUserIds() { return new int[] {USER_ID}; } @@ -403,30 +415,30 @@ public class AppStandbyControllerTests { false)); } - private void reportEvent(AppStandbyController controller, int eventType, - long elapsedTime) { + private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime, + String packageName) { // Back to ACTIVE on event mInjector.mElapsedRealtime = elapsedTime; UsageEvents.Event ev = new UsageEvents.Event(); - ev.mPackage = PACKAGE_1; + ev.mPackage = packageName; ev.mEventType = eventType; controller.reportEvent(ev, elapsedTime, USER_ID); } - private int getStandbyBucket(AppStandbyController controller) { - return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, + private int getStandbyBucket(AppStandbyController controller, String packageName) { + return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime, true); } private void assertBucket(int bucket) { - assertEquals(bucket, getStandbyBucket(mController)); + assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testBuckets() throws Exception { assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); // ACTIVE bucket assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); @@ -443,7 +455,7 @@ public class AppStandbyControllerTests { // RARE bucket assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); - reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1); + reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1); assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); @@ -452,12 +464,48 @@ public class AppStandbyControllerTests { } @Test + public void testSetAppStandbyBucket() throws Exception { + // For a known package, standby bucket should be set properly + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_MAIN_TIMEOUT, HOUR_MS); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); + + // For an unknown package, standby bucket should not be set, hence NEVER is returned + // Ensure the unknown package is not already in history by removing it + mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID); + isPackageInstalled = false; // Mock package is not installed + mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_MAIN_TIMEOUT, HOUR_MS); + isPackageInstalled = true; // Reset mocked variable for other tests + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN)); + } + + @Test + public void testAppStandbyBucketOnInstallAndUninstall() throws Exception { + // On package install, standby bucket should be ACTIVE + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_UNKNOWN)); + + // On uninstall, package should not exist in history and should return a NEVER bucket + mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID); + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN)); + // Ensure uninstalled app is not in history + List<AppStandbyInfo> buckets = mController.getAppStandbyBuckets(USER_ID); + for(AppStandbyInfo bucket : buckets) { + if (bucket.mPackageName.equals(PACKAGE_UNKNOWN)) { + fail("packageName found in app idle history after uninstall."); + } + } + } + + @Test public void testScreenTimeAndBuckets() throws Exception { mInjector.setDisplayOn(false); assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); // ACTIVE bucket assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); @@ -468,7 +516,7 @@ public class AppStandbyControllerTests { // RARE bucket, should fail because the screen wasn't ON. mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; mController.checkIdleStates(USER_ID); - assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); mInjector.setDisplayOn(true); assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); @@ -477,7 +525,7 @@ public class AppStandbyControllerTests { @Test public void testForcedIdle() throws Exception { mController.forceIdleState(PACKAGE_1, USER_ID, true); - assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); mController.forceIdleState(PACKAGE_1, USER_ID, false); @@ -488,35 +536,35 @@ public class AppStandbyControllerTests { @Test public void testNotificationEvent() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mInjector.mElapsedRealtime = 1; - reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mController.forceIdleState(PACKAGE_1, USER_ID, true); - reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); + reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testSlicePinnedEvent() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mInjector.mElapsedRealtime = 1; - reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mController.forceIdleState(PACKAGE_1, USER_ID, true); - reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); + reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testSlicePinnedPrivEvent() throws Exception { mController.forceIdleState(PACKAGE_1, USER_ID, true); - reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } @Test @@ -524,28 +572,28 @@ public class AppStandbyControllerTests { // Set it to timeout or usage, so that prediction can override it mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_TIMEOUT, HOUR_MS); - assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_MAIN_PREDICTED, HOUR_MS); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); // Fast forward 12 hours mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD; mController.checkIdleStates(USER_ID); // Should still be in predicted bucket, since prediction timeout is 1 day since prediction - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); // Fast forward two more hours mInjector.mElapsedRealtime += 2 * HOUR_MS; mController.checkIdleStates(USER_ID); // Should have now applied prediction timeout - assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); // Fast forward RARE bucket mInjector.mElapsedRealtime += RARE_THRESHOLD; mController.checkIdleStates(USER_ID); // Should continue to apply prediction timeout - assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); } @Test @@ -553,33 +601,33 @@ public class AppStandbyControllerTests { // Can force to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_FORCED, 1 * HOUR_MS); - assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); // Prediction can't override FORCED reason mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, REASON_MAIN_FORCED, 1 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, REASON_MAIN_PREDICTED, 1 * HOUR_MS); - assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1)); // Prediction can't override NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_DEFAULT, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_MAIN_PREDICTED, 2 * HOUR_MS); - assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); // Prediction can't set to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_MAIN_USAGE, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_PREDICTED, 2 * HOUR_MS); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testTimeout() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mInjector.mElapsedRealtime = 2000; @@ -601,10 +649,10 @@ public class AppStandbyControllerTests { @Test public void testCascadingTimeouts() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); - reportEvent(mController, NOTIFICATION_SEEN, 1000); + reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, @@ -622,14 +670,15 @@ public class AppStandbyControllerTests { @Test public void testOverlappingTimeouts() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); - reportEvent(mController, NOTIFICATION_SEEN, 1000); + reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Overlapping USER_INTERACTION before previous one times out - reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000); + reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000, + PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Still in ACTIVE after first USER_INTERACTION times out @@ -654,14 +703,14 @@ public class AppStandbyControllerTests { public void testSystemInteractionTimeout() throws Exception { setChargingState(mController, false); - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); // Fast forward to RARE mInjector.mElapsedRealtime = RARE_THRESHOLD + 100; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_RARE); // Trigger a SYSTEM_INTERACTION and verify bucket - reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime); + reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Verify it's still in ACTIVE close to end of timeout @@ -677,11 +726,11 @@ public class AppStandbyControllerTests { @Test public void testPredictionNotOverridden() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000; - reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); + reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Falls back to WORKING_SET @@ -703,7 +752,7 @@ public class AppStandbyControllerTests { @Test public void testPredictionStrikesBack() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Predict to FREQUENT @@ -714,7 +763,7 @@ public class AppStandbyControllerTests { // Add a short timeout event mInjector.mElapsedRealtime += 1000; - reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime); + reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mInjector.mElapsedRealtime += 1000; mController.checkIdleStates(USER_ID); 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 4e007c2d9929..3266b8b92a19 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -1689,7 +1689,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testGetNotificationChannelFromPrivilegedListener_success() throws Exception { + public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); List<String> associations = new ArrayList<>(); associations.add("a"); @@ -1703,7 +1703,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception { + public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); List<String> associations = new ArrayList<>(); when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); @@ -1721,6 +1721,38 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testGetNotificationChannelFromPrivilegedListener_assistant_success() + throws Exception { + mService.setPreferencesHelper(mPreferencesHelper); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>()); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + + verify(mPreferencesHelper, times(1)).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + + @Test + public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception { + mService.setPreferencesHelper(mPreferencesHelper); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>()); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); + + try { + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listeners that don't have a companion device shouldn't be able to call this"); + } catch (SecurityException e) { + // pass + } + + verify(mPreferencesHelper, never()).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + + @Test public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); List<String> associations = new ArrayList<>(); diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java index 4e997323a30e..bc54a5d2c499 100644 --- a/services/usage/java/com/android/server/usage/AppIdleHistory.java +++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java @@ -320,14 +320,7 @@ public class AppIdleHistory { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); - if (appUsageHistory == null) { - return false; // Default to not idle - } else { - return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE; - // Whether or not it's passed will now be externally calculated and the - // bucket will be pushed to the history using setAppStandbyBucket() - //return hasPassedThresholds(appUsageHistory, elapsedRealtime); - } + return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE; } public AppUsageHistory getAppUsageHistory(String packageName, int userId, @@ -404,17 +397,19 @@ public class AppIdleHistory { public long getTimeSinceLastJobRun(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = - getPackageHistory(userHistory, packageName, elapsedRealtime, true); + getPackageHistory(userHistory, packageName, elapsedRealtime, false); // Don't adjust the default, else it'll wrap around to a positive value - if (appUsageHistory.lastJobRunTime == Long.MIN_VALUE) return Long.MAX_VALUE; + if (appUsageHistory == null || appUsageHistory.lastJobRunTime == Long.MIN_VALUE) { + return Long.MAX_VALUE; + } return getElapsedTime(elapsedRealtime) - appUsageHistory.lastJobRunTime; } public int getAppStandbyBucket(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = - getPackageHistory(userHistory, packageName, elapsedRealtime, true); - return appUsageHistory.currentBucket; + getPackageHistory(userHistory, packageName, elapsedRealtime, false); + return appUsageHistory == null ? STANDBY_BUCKET_NEVER : appUsageHistory.currentBucket; } public ArrayList<AppStandbyInfo> getAppStandbyBuckets(int userId, boolean appIdleEnabled) { diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 02ad3a8772f8..6a74564367b8 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -1161,6 +1161,10 @@ public class AppStandbyController { void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout) { synchronized (mAppIdleLock) { + // If the package is not installed, don't allow the bucket to be set. + if (!mInjector.isPackageInstalled(packageName, 0, userId)) { + return; + } AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED; @@ -1594,6 +1598,10 @@ public class AppStandbyController { return mPackageManagerInternal.isPackageEphemeral(userId, packageName); } + boolean isPackageInstalled(String packageName, int flags, int userId) { + return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0; + } + int[] getRunningUserIds() throws RemoteException { return ActivityManager.getService().getRunningUserIds(); } |