summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/current.txt41
-rw-r--r--cmds/incidentd/Android.mk6
-rw-r--r--cmds/statsd/src/atoms.proto26
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp3
-rw-r--r--config/hiddenapi-light-greylist.txt263
-rw-r--r--config/hiddenapi-vendor-list.txt8
-rw-r--r--core/java/android/app/FragmentTransition.java5
-rw-r--r--core/java/android/app/NotificationChannel.java5
-rw-r--r--core/java/android/content/ContentProvider.java42
-rw-r--r--core/java/android/os/UserManager.java4
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java6
-rw-r--r--core/java/android/text/Layout.java36
-rw-r--r--core/java/android/text/style/TextAppearanceSpan.java4
-rw-r--r--core/java/android/transition/TransitionManager.java1
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java40
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodDebug.java158
-rw-r--r--core/java/com/android/internal/inputmethod/StartInputReason.java92
-rw-r--r--core/java/com/android/internal/inputmethod/UnbindReason.java69
-rw-r--r--core/java/com/android/internal/view/IInputMethodClient.aidl1
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/java/com/android/internal/view/InputMethodClient.java169
-rw-r--r--core/res/res/values/strings.xml18
-rw-r--r--core/tests/coretests/assets/fonts/1em_bidi_font.ttfbin0 -> 2076 bytes
-rw-r--r--core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java166
-rw-r--r--graphics/java/android/graphics/Typeface.java3
-rw-r--r--graphics/java/android/graphics/fonts/Font.java143
-rw-r--r--graphics/java/android/graphics/fonts/FontFamily.java2
-rw-r--r--graphics/java/android/graphics/fonts/FontStyle.java256
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java3
-rw-r--r--libs/hwui/Android.bp3
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp2
-rw-r--r--libs/hwui/tests/macrobench/main.cpp2
-rwxr-xr-xmedia/java/android/mtp/MtpDatabase.java7
-rw-r--r--media/jni/Android.bp1
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/AgingHelper.java2
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java8
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java9
-rw-r--r--services/core/java/com/android/server/VibratorService.java63
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java46
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java32
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java64
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java77
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java141
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java69
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java26
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java35
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java72
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java2
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverController.java6
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java109
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java (renamed from services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java)24
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java57
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java141
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java36
-rw-r--r--services/usage/java/com/android/server/usage/AppIdleHistory.java19
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java8
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
new file mode 100644
index 000000000000..459925433349
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/1em_bidi_font.ttf
Binary files differ
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();
}