summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/statsd/src/atoms.proto39
-rw-r--r--cmds/statsd/src/external/GpuStatsPuller.cpp3
-rw-r--r--cmds/statsd/tests/external/GpuStatsPuller_test.cpp11
-rw-r--r--core/java/android/app/Activity.java20
-rw-r--r--core/java/android/app/ActivityManager.java20
-rw-r--r--core/java/android/app/ContextImpl.java64
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl9
-rw-r--r--core/java/android/app/IRequestFinishCallback.aidl27
-rw-r--r--core/java/android/app/ITaskStackListener.aidl8
-rw-r--r--core/java/android/app/TaskStackListener.java5
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/content/pm/PackageInstaller.java13
-rw-r--r--core/java/android/content/pm/PackageManager.java5
-rw-r--r--core/java/android/os/GraphicsEnvironment.java23
-rw-r--r--core/java/android/permission/PermissionManager.java122
-rw-r--r--core/java/android/provider/CalendarContract.java4
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java63
-rw-r--r--core/java/android/service/autofill/augmented/FillCallback.java6
-rw-r--r--core/java/android/service/autofill/augmented/Helper.java48
-rw-r--r--core/java/android/transition/Transition.java23
-rw-r--r--core/java/android/view/SurfaceView.java215
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java20
-rw-r--r--core/java/com/android/internal/policy/DecorView.java3
-rw-r--r--core/jni/android_net_NetUtils.cpp4
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp6
-rw-r--r--core/proto/android/stats/connectivity/resolv_stats.proto182
-rw-r--r--core/proto/android/stats/dnsresolver/Android.bp25
-rw-r--r--core/proto/android/stats/dnsresolver/dns_resolver.proto214
-rw-r--r--core/res/res/anim/resolver_close_anim.xml28
-rw-r--r--core/res/res/anim/resolver_launch_anim.xml27
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/res/res/values/themes_device_defaults.xml11
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java29
-rw-r--r--media/java/android/media/RingtoneManager.java56
-rw-r--r--media/java/android/media/session/MediaController.java7
-rw-r--r--media/java/android/media/session/MediaSession.java3
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml20
-rw-r--r--packages/SystemUI/res-keyguard/drawable/analog_frame.xml6
-rw-r--r--packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml9
-rw-r--r--packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml9
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml6
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml8
-rw-r--r--packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml25
-rw-r--r--packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml25
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header.xml66
-rw-r--r--packages/SystemUI/res/values-night/colors.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/ids.xml6
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java229
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/Stroke.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java246
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java265
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java215
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java70
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto68
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java24
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java7
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java4
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java3
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java17
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java13
-rw-r--r--services/core/java/com/android/server/display/color/ColorDisplayService.java33
-rw-r--r--services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java48
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java12
-rw-r--r--services/core/java/com/android/server/om/DumpState.java63
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java80
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java8
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java94
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerShellCommand.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java57
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java9
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java50
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java6
-rw-r--r--services/core/java/com/android/server/pm/ShortcutUser.java22
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java29
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java23
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java27
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java27
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp21
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java191
-rw-r--r--services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java33
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java10
-rw-r--r--telephony/java/android/telephony/SmsManager.java41
-rw-r--r--telephony/java/android/telephony/UiccSlotInfo.java4
-rw-r--r--telephony/java/android/telephony/emergency/EmergencyNumber.java37
-rw-r--r--tools/aapt2/Android.bp1
-rw-r--r--tools/aapt2/ResourceValues_test.cpp52
-rw-r--r--tools/aapt2/link/TableMerger_test.cpp48
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java13
131 files changed, 3173 insertions, 1244 deletions
diff --git a/Android.bp b/Android.bp
index abf95a8ebc58..2ccddd25c9de 100644
--- a/Android.bp
+++ b/Android.bp
@@ -73,6 +73,7 @@ java_defaults {
"core/java/android/app/IInstrumentationWatcher.aidl",
"core/java/android/app/INotificationManager.aidl",
"core/java/android/app/IProcessObserver.aidl",
+ "core/java/android/app/IRequestFinishCallback.aidl",
"core/java/android/app/ISearchManager.aidl",
"core/java/android/app/ISearchManagerCallback.aidl",
"core/java/android/app/IServiceConnection.aidl",
diff --git a/api/test-current.txt b/api/test-current.txt
index 5dc7929d06df..181932cf1260 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -725,7 +725,6 @@ package android.content.pm {
field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
- field public static boolean RESTRICTED_PERMISSIONS_ENABLED;
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 3a84b79fc681..033dbf7aa4a5 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -41,7 +41,7 @@ import "frameworks/base/core/proto/android/server/location/enums.proto";
import "frameworks/base/core/proto/android/service/procstats_enum.proto";
import "frameworks/base/core/proto/android/service/usb.proto";
import "frameworks/base/core/proto/android/stats/connectivity/network_stack.proto";
-import "frameworks/base/core/proto/android/stats/connectivity/resolv_stats.proto";
+import "frameworks/base/core/proto/android/stats/dnsresolver/dns_resolver.proto";
import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
@@ -5109,36 +5109,36 @@ message AppCompacted {
* Logs a DNS lookup operation initiated by the system resolver on behalf of an application
* invoking native APIs such as getaddrinfo() or Java APIs such as Network#getAllByName().
*
- * The top-level message represents the entire lookup operation, which may result one or more
- * queries to the recursive DNS resolvers. Those are individually logged in DnsQueryEvent to
- * enable computing error rates and network latency and timeouts broken up by query type,
- * transport, network interface, etc.
+ * The NetworkDnsEventReported message represents the entire lookup operation, which may
+ * result one or more queries to the recursive DNS resolvers. Those are individually logged
+ * in DnsQueryEvents to enable computing error rates and network latency and timeouts
+ * broken up by query type, transport, network interface, etc.
*/
message NetworkDnsEventReported {
+ optional android.stats.dnsresolver.EventType event_type = 1;
- optional android.stats.connectivity.EventType event_type = 1;
-
- optional android.stats.connectivity.ReturnCode return_code = 2;
+ optional android.stats.dnsresolver.ReturnCode return_code = 2;
// The latency in microseconds of the entire DNS lookup operation.
optional int32 latency_micros = 3;
- optional android.stats.connectivity.DnsQueryEventRe dns_query_event_re = 4 [(log_mode) = MODE_BYTES];
+ // Only valid for event_type = EVENT_GETADDRINFO.
+ optional int32 hints_ai_flags = 4;
- // ResNSend flags defined in android/multinetwork.h
- optional int32 flags = 5;
+ // Flags passed to android_res_nsend() defined in multinetwork.h
+ // Only valid for event_type = EVENT_RESNSEND.
+ optional int32 res_nsend_flags = 5;
- optional android.net.NetworkCapabilitiesProto.Transport network_type = 6;
+ optional android.stats.dnsresolver.Transport network_type = 6;
// The DNS over TLS mode on a specific netId.
- optional android.stats.connectivity.PrivateDnsModes private_dns_modes = 7;
+ optional android.stats.dnsresolver.PrivateDnsModes private_dns_modes = 7;
// Additional pass-through fields opaque to statsd.
// The DNS resolver Mainline module can add new fields here without requiring an OS update.
- optional android.stats.connectivity.DnsCallEvent dns_call_event = 8 [(log_mode) = MODE_BYTES];
+ optional android.stats.dnsresolver.DnsQueryEvents dns_query_events = 8 [(log_mode) = MODE_BYTES];
}
-
/**
* Logs when a data stall event occurs.
*
@@ -6131,6 +6131,15 @@ message GpuStatsGlobalInfo {
// Total count of the Vulkan driver fails to be loaded.
optional int64 vk_loading_failure_count = 8;
+
+ // Api version of the system Vulkan driver.
+ optional int32 vulkan_version = 9;
+
+ // Api version of the system CPU Vulkan driver.
+ optional int32 cpu_vulkan_version = 10;
+
+ // Api version of the system GLES driver.
+ optional int32 gles_version = 11;
}
/**
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index 3fa932fddd04..876383c16863 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -65,6 +65,9 @@ static bool pullGpuStatsGlobalInfo(const sp<IGpuService>& gpuService,
if (!event->write((int64_t)info.glLoadingFailureCount)) return false;
if (!event->write((int64_t)info.vkLoadingCount)) return false;
if (!event->write((int64_t)info.vkLoadingFailureCount)) return false;
+ if (!event->write(info.vulkanVersion)) return false;
+ if (!event->write(info.cpuVulkanVersion)) return false;
+ if (!event->write(info.glesVersion)) return false;
event->init();
data->emplace_back(event);
}
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
index 8625487d1aca..2acfb8354905 100644
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -48,7 +48,10 @@ static const int64_t GL_DRIVER_LOADING_TIME_1 = 666;
static const int64_t VK_DRIVER_LOADING_TIME_0 = 777;
static const int64_t VK_DRIVER_LOADING_TIME_1 = 888;
static const int64_t VK_DRIVER_LOADING_TIME_2 = 999;
-static const size_t NUMBER_OF_VALUES_GLOBAL = 8;
+static const int32_t VULKAN_VERSION = 1;
+static const int32_t CPU_VULKAN_VERSION = 2;
+static const int32_t GLES_VERSION = 3;
+static const size_t NUMBER_OF_VALUES_GLOBAL = 11;
static const size_t NUMBER_OF_VALUES_APP = 4;
// clang-format on
@@ -93,6 +96,9 @@ TEST_F(GpuStatsPuller_test, PullGpuStatsGlobalInfo) {
EXPECT_TRUE(event->write(GL_LOADING_FAILURE_COUNT));
EXPECT_TRUE(event->write(VK_LOADING_COUNT));
EXPECT_TRUE(event->write(VK_LOADING_FAILURE_COUNT));
+ EXPECT_TRUE(event->write(VULKAN_VERSION));
+ EXPECT_TRUE(event->write(CPU_VULKAN_VERSION));
+ EXPECT_TRUE(event->write(GLES_VERSION));
event->init();
inData.emplace_back(event);
MockGpuStatsPuller mockPuller(android::util::GPU_STATS_GLOBAL_INFO, &inData);
@@ -110,6 +116,9 @@ TEST_F(GpuStatsPuller_test, PullGpuStatsGlobalInfo) {
EXPECT_EQ(GL_LOADING_FAILURE_COUNT, outData[0]->getValues()[5].mValue.long_value);
EXPECT_EQ(VK_LOADING_COUNT, outData[0]->getValues()[6].mValue.long_value);
EXPECT_EQ(VK_LOADING_FAILURE_COUNT, outData[0]->getValues()[7].mValue.long_value);
+ EXPECT_EQ(VULKAN_VERSION, outData[0]->getValues()[8].mValue.int_value);
+ EXPECT_EQ(CPU_VULKAN_VERSION, outData[0]->getValues()[9].mValue.int_value);
+ EXPECT_EQ(GLES_VERSION, outData[0]->getValues()[10].mValue.int_value);
}
TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2914f6c5abf2..c08ed268833b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3666,7 +3666,25 @@ public class Activity extends ContextThemeWrapper
FragmentManager fragmentManager = mFragments.getFragmentManager();
- if (fragmentManager.isStateSaved() || !fragmentManager.popBackStackImmediate()) {
+ if (!fragmentManager.isStateSaved() && fragmentManager.popBackStackImmediate()) {
+ return;
+ }
+ if (!isTaskRoot()) {
+ // If the activity is not the root of the task, allow finish to proceed normally.
+ finishAfterTransition();
+ return;
+ }
+ try {
+ // Inform activity task manager that the activity received a back press
+ // while at the root of the task. This call allows ActivityTaskManager
+ // to intercept or defer finishing.
+ ActivityTaskManager.getService().onBackPressedOnTaskRoot(mToken,
+ new IRequestFinishCallback.Stub() {
+ public void requestFinish() {
+ finishAfterTransition();
+ }
+ });
+ } catch (RemoteException e) {
finishAfterTransition();
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a36b167004f8..17368b789645 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -64,7 +64,6 @@ import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.permission.PermissionManager;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Singleton;
@@ -3739,7 +3738,6 @@ public class ActivityManager {
}
// Isolated processes don't get any permissions.
if (UserHandle.isIsolated(uid)) {
- PermissionManager.addPermissionDenialHint("uid " + uid + " is isolated");
return PackageManager.PERMISSION_DENIED;
}
// If there is a uid that owns whatever is being accessed, it has
@@ -3755,26 +3753,24 @@ public class ActivityManager {
Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
here);
*/
- PermissionManager.addPermissionDenialHint(
- "Target is not exported. owningUid=" + owningUid);
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
- return checkUidPermission(permission, uid);
+ try {
+ return AppGlobals.getPackageManager()
+ .checkUidPermission(permission, uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** @hide */
public static int checkUidPermission(String permission, int uid) {
try {
- List<String> hints = PermissionManager.getPermissionDenialHints();
- if (hints == null) {
- return AppGlobals.getPackageManager().checkUidPermission(permission, uid);
- } else {
- return AppGlobals.getPackageManager()
- .checkUidPermissionWithDenialHintForwarding(permission, uid, hints);
- }
+ return AppGlobals.getPackageManager()
+ .checkUidPermission(permission, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 931e3553c2b6..41a4fba0434c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -68,7 +68,6 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -99,7 +98,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteOrder;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -1830,17 +1828,11 @@ class ContextImpl extends Context {
}
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
+ permission);
- PermissionManager.addPermissionDenialHint("Missing ActivityManager");
return PackageManager.PERMISSION_DENIED;
}
try {
- List<String> hints = PermissionManager.getPermissionDenialHints();
- if (hints == null) {
- return am.checkPermission(permission, pid, uid);
- } else {
- return am.checkPermissionWithDenialHintForwarding(permission, pid, uid, hints);
- }
+ return am.checkPermission(permission, pid, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1897,61 +1889,43 @@ class ContextImpl extends Context {
String permission, int resultOfCheck,
boolean selfToo, int uid, String message) {
if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
- List<String> hints = PermissionManager.getPermissionDenialHints();
throw new SecurityException(
(message != null ? (message + ": ") : "") +
(selfToo
? "Neither user " + uid + " nor current process has "
- : "uid " + uid + " does not have ")
- + permission + "."
- + (hints == null ? "" : " Hints: " + hints));
+ : "uid " + uid + " does not have ") +
+ permission +
+ ".");
}
}
@Override
public void enforcePermission(
String permission, int pid, int uid, String message) {
- List<String> prev = PermissionManager.collectPermissionDenialHints(this, uid);
- try {
- enforce(permission,
- checkPermission(permission, pid, uid),
- false,
- uid,
- message);
- } finally {
- PermissionManager.resetPermissionDenialHints(prev);
- }
+ enforce(permission,
+ checkPermission(permission, pid, uid),
+ false,
+ uid,
+ message);
}
@Override
public void enforceCallingPermission(String permission, String message) {
- List<String> prev = PermissionManager.collectPermissionDenialHints(this,
- Binder.getCallingUid());
- try {
- enforce(permission,
- checkCallingPermission(permission),
- false,
- Binder.getCallingUid(),
- message);
- } finally {
- PermissionManager.resetPermissionDenialHints(prev);
- }
+ enforce(permission,
+ checkCallingPermission(permission),
+ false,
+ Binder.getCallingUid(),
+ message);
}
@Override
public void enforceCallingOrSelfPermission(
String permission, String message) {
- List<String> prev = PermissionManager.collectPermissionDenialHints(this,
- Binder.getCallingUid());
- try {
- enforce(permission,
- checkCallingOrSelfPermission(permission),
- true,
- Binder.getCallingUid(),
- message);
- } finally {
- PermissionManager.resetPermissionDenialHints(prev);
- }
+ enforce(permission,
+ checkCallingOrSelfPermission(permission),
+ true,
+ Binder.getCallingUid(),
+ message);
}
@Override
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f82536f65ddb..48ca71690a1b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -194,7 +194,6 @@ interface IActivityManager {
int getProcessLimit();
@UnsupportedAppUsage
int checkPermission(in String permission, int pid, int uid);
- int checkPermissionWithDenialHintForwarding(in String permission, int pid, int uid, inout List<String> permissionDenialHints);
int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId,
in IBinder callerToken);
void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 7953d42514fc..26720fca4df8 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -26,6 +26,7 @@ import android.app.IAppTask;
import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
+import android.app.IRequestFinishCallback;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
import android.app.ITaskStackListener;
@@ -484,4 +485,12 @@ interface IActivityTaskManager {
* @param activityToken The token of the target activity to restart.
*/
void restartActivityProcessIfVisible(in IBinder activityToken);
+
+ /**
+ * Reports that an Activity received a back key press when there were no additional activities
+ * on the back stack. If the Activity should be finished, the callback will be invoked. A
+ * callback is used instead of finishing the activity directly from the server such that the
+ * client may perform actions prior to finishing.
+ */
+ void onBackPressedOnTaskRoot(in IBinder activityToken, in IRequestFinishCallback callback);
}
diff --git a/core/java/android/app/IRequestFinishCallback.aidl b/core/java/android/app/IRequestFinishCallback.aidl
new file mode 100644
index 000000000000..3270565727d9
--- /dev/null
+++ b/core/java/android/app/IRequestFinishCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.app;
+
+/**
+ * This callback allows ActivityTaskManager to ask the calling Activity
+ * to finish in response to a call to onBackPressedOnTaskRoot.
+ *
+ * {@hide}
+ */
+oneway interface IRequestFinishCallback {
+ void requestFinish();
+}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 841ff6a3f12e..1fdc8ca5b291 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -161,4 +161,12 @@ oneway interface ITaskStackListener {
* @see com.android.server.wm.AppWindowToken#inSizeCompatMode
*/
void onSizeCompatModeActivityChanged(int displayId, in IBinder activityToken);
+
+ /**
+ * Reports that an Activity received a back key press when there were no additional activities
+ * on the back stack.
+ *
+ * @param taskInfo info about the task which received the back press
+ */
+ void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index a4a97c4cac1d..00f3ad58afa6 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -168,4 +168,9 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken)
throws RemoteException {
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)
+ throws RemoteException {
+ }
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 225eec13d6eb..6ab4657d727d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -108,7 +108,6 @@ interface IPackageManager {
@UnsupportedAppUsage
int checkPermission(String permName, String pkgName, int userId);
- int checkUidPermissionWithDenialHintForwarding(String permName, int uid, inout List<String> permissionDenialHints);
int checkUidPermission(String permName, int uid);
@UnsupportedAppUsage
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a8815ec6cfaa..89eabc285e38 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1278,7 +1278,7 @@ public class PackageInstaller {
public int mode = MODE_INVALID;
/** {@hide} */
@UnsupportedAppUsage
- public int installFlags;
+ public int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
/** {@hide} */
public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
/** {@hide} */
@@ -1513,18 +1513,21 @@ public class PackageInstaller {
* state of the permission can be determined only at install time and cannot be
* changed on updated or at a later point via the package manager APIs.
*
+ * <p>Initially, all restricted permissions are whitelisted but you can change
+ * which ones are whitelisted by calling this method or the corresponding ones
+ * on the {@link PackageManager}.
+ *
* @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
* @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
*/
public void setWhitelistedRestrictedPermissions(@Nullable Set<String> permissions) {
if (permissions == RESTRICTED_PERMISSIONS_ALL) {
installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
- }
- if (permissions != null) {
- this.whitelistedRestrictedPermissions = new ArrayList<>(permissions);
+ whitelistedRestrictedPermissions = null;
} else {
installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
- this.whitelistedRestrictedPermissions = null;
+ whitelistedRestrictedPermissions = (permissions != null)
+ ? new ArrayList<>(permissions) : null;
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index dd5ca6706316..40561f02d55f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -86,11 +86,6 @@ public abstract class PackageManager {
/** {@hide} */
public static final boolean APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = true;
- /** {@hide} */
- @TestApi
- // STOPSHIP: Remove this once we get a Play prebuilt.
- public static boolean RESTRICTED_PERMISSIONS_ENABLED = false;
-
/**
* This exception is thrown when a given package, application, or component
* name cannot be found.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 232869d7aefc..7dbc16a56a7b 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -71,6 +71,8 @@ public class GraphicsEnvironment {
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message";
private static final String GAME_DRIVER_WHITELIST_ALL = "*";
+ private static final int VULKAN_1_0 = 0x00400000;
+ private static final int VULKAN_1_1 = 0x00401000;
// GAME_DRIVER_ALL_APPS
// 0: Default (Invalid values fallback to default as well)
@@ -99,7 +101,8 @@ public class GraphicsEnvironment {
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
if (!chooseDriver(context, coreSettings, pm, packageName)) {
setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
- SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
+ SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName,
+ getVulkanVersion(pm));
}
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
@@ -200,6 +203,20 @@ public class GraphicsEnvironment {
return true;
}
+ private static int getVulkanVersion(PackageManager pm) {
+ // PackageManager doesn't have an API to retrieve the version of a specific feature, and we
+ // need to avoid retrieving all system features here and looping through them.
+ if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_1)) {
+ return VULKAN_1_1;
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_0)) {
+ return VULKAN_1_0;
+ }
+
+ return 0;
+ }
+
/**
* Check whether application is debuggable
*/
@@ -791,7 +808,7 @@ public class GraphicsEnvironment {
// driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
// Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode,
- Long.parseLong(driverBuildTime.substring(1)), packageName);
+ Long.parseLong(driverBuildTime.substring(1)), packageName, 0);
return true;
}
@@ -815,7 +832,7 @@ public class GraphicsEnvironment {
private static native void setDebugLayersGLES(String layers);
private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
private static native void setGpuStats(String driverPackageName, String driverVersionName,
- long driverVersionCode, long driverBuildTime, String appPackageName);
+ long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
FileDescriptor rulesFd, long rulesOffset, long rulesLength);
private static native boolean getShouldUseAngle(String packageName);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 55bb3fe1817c..2a41c2065c46 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -19,22 +19,15 @@ package android.permission;
import android.Manifest;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
import com.android.internal.annotations.Immutable;
-import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import java.util.ArrayList;
@@ -49,8 +42,6 @@ import java.util.Objects;
@SystemApi
@SystemService(Context.PERMISSION_SERVICE)
public final class PermissionManager {
- private static final String LOG_TAG = PermissionManager.class.getSimpleName();
-
/**
* {@link android.content.pm.PackageParser} needs access without having a {@link Context}.
*
@@ -63,119 +54,6 @@ public final class PermissionManager {
private final IPackageManager mPackageManager;
- /** Permission denials added via {@link addPermissionDenial} */
- private static final ThreadLocal<List<String>> sPermissionDenialHints = new ThreadLocal<>();
-
- /**
- * Report a hint that might explain why a permission check returned
- * {@link PackageManager#PERMISSION_DENIED}.
- *
- * <p>Hints are only collected if enabled via {@link collectPermissionDenialHints} or
- * when a non-null value was passed to {@link resetPermissionDenialHints}
- *
- * @param hint A description of the reason
- *
- * @hide
- */
- public static void addPermissionDenialHint(@NonNull String hint) {
- List<String> hints = sPermissionDenialHints.get();
- if (hints == null) {
- return;
- }
-
- hints.add(hint);
- }
-
- /**
- * @return hints added via {@link #addPermissionDenialHint(String)} on this thread before.
- *
- * @hide
- */
- public static @Nullable List<String> getPermissionDenialHints() {
- if (Build.IS_USER) {
- return null;
- }
-
- return sPermissionDenialHints.get();
- }
-
- /**
- * Reset the permission denial hints for this thread.
- *
- * @param initial The initial values. If not null, enabled collection on this thread.
- *
- * @return the previously collected hints
- *
- * @hide
- */
- public static @Nullable List<String> resetPermissionDenialHints(
- @Nullable List<String> initial) {
- List<String> prev = getPermissionDenialHints();
- if (initial == null) {
- sPermissionDenialHints.remove();
- } else {
- sPermissionDenialHints.set(initial);
- }
- return prev;
- }
-
- /**
- * Enable permission denial hint collection if package is in
- * {@link Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK}
- *
- * @param context A context to use
- * @param uid The uid the permission check is for.
- *
- * @return the previously collected hints
- *
- * @hide
- */
- public static @Nullable List<String> collectPermissionDenialHints(@NonNull Context context,
- int uid) {
- List<String> prev = getPermissionDenialHints();
-
- if (Build.IS_USER) {
- return prev;
- }
-
- ContentResolver cr = context.getContentResolver();
- if (cr == null) {
- return prev;
- }
-
- String debugSetting;
- try {
- debugSetting = Settings.Secure.getString(cr,
- Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK);
- } catch (IllegalStateException e) {
- Log.e(LOG_TAG, "Cannot access settings", e);
- return prev;
- }
- if (debugSetting == null) {
- return prev;
- }
- String[] debugPkgs = debugSetting.split(",");
-
- PackageManager pm = context.getPackageManager();
- if (pm == null) {
- return prev;
- }
-
- String[] packages = pm.getPackagesForUid(uid);
- if (packages == null) {
- return prev;
- }
-
- for (String pkg : packages) {
- if (ArrayUtils.contains(debugPkgs, pkg)) {
- sPermissionDenialHints.set(new ArrayList<>(0));
- break;
- }
- }
-
- return prev;
- }
-
/**
* Creates a new instance.
*
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index fa244e480e11..2f68eb475e7a 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -187,6 +187,10 @@ public final class CalendarContract {
* {@link android.database.ContentObserver} for this URL in the primary profile will be
* notified when there is a change in the managed profile calendar provider.
*
+ * <p>Throw UnsupportedOperationException if another profile doesn't exist or is disabled, or
+ * if the calling package is not whitelisted to access cross-profile calendar, or if the
+ * feature has been disabled by the user in Settings.
+ *
* @see Events#ENTERPRISE_CONTENT_URI
* @see Calendars#ENTERPRISE_CONTENT_URI
* @see Instances#ENTERPRISE_CONTENT_URI
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dbc62f4a12fa..7c5a1fb5f787 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5786,16 +5786,6 @@ public final class Settings {
public static final String ANDROID_ID = "android_id";
/**
- * Comma separated list packages to enable collection of permission denial hints for.
- *
- * @hide
- *
- * @see android.permission.PermissionManager#collectPermissionDenialHints(Context, int)
- */
- public static final String DEBUG_PACKAGE_PERMISSION_CHECK =
- "debug_package_permission_check";
-
- /**
* @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead
*/
@Deprecated
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 656127ad77a9..87e369f20d58 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -15,6 +15,9 @@
*/
package android.service.autofill.augmented;
+import static android.service.autofill.augmented.Helper.logResponse;
+import static android.util.TimeUtils.formatDuration;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.CallSuper;
@@ -38,9 +41,7 @@ import android.os.SystemClock;
import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseArray;
-import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -48,6 +49,7 @@ import android.view.autofill.IAugmentedAutofillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -84,6 +86,9 @@ public abstract class AugmentedAutofillService extends Service {
private SparseArray<AutofillProxy> mAutofillProxies;
+ // Used for metrics / debug only
+ private ComponentName mServiceComponentName;
+
private final IAugmentedAutofillService mInterface = new IAugmentedAutofillService.Stub() {
@Override
@@ -125,6 +130,7 @@ public abstract class AugmentedAutofillService extends Service {
/** @hide */
@Override
public final IBinder onBind(Intent intent) {
+ mServiceComponentName = intent.getComponent();
if (SERVICE_INTERFACE.equals(intent.getAction())) {
return mInterface.asBinder();
}
@@ -215,8 +221,9 @@ public abstract class AugmentedAutofillService extends Service {
final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport);
AutofillProxy proxy = mAutofillProxies.get(sessionId);
if (proxy == null) {
- proxy = new AutofillProxy(sessionId, client, taskId, componentName, focusedId,
- focusedValue, requestTime, callback, cancellationSignal);
+ proxy = new AutofillProxy(sessionId, client, taskId, mServiceComponentName,
+ componentName, focusedId, focusedValue, requestTime, callback,
+ cancellationSignal);
mAutofillProxies.put(sessionId, proxy);
} else {
// TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
@@ -272,6 +279,8 @@ public abstract class AugmentedAutofillService extends Service {
@Override
/** @hide */
protected final void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print("Service component: "); pw.println(
+ ComponentName.flattenToShortString(mServiceComponentName));
if (mAutofillProxies != null) {
final int size = mAutofillProxies.size();
pw.print("Number proxies: "); pw.println(size);
@@ -301,12 +310,12 @@ public abstract class AugmentedAutofillService extends Service {
/** @hide */
static final class AutofillProxy {
- static final int REPORT_EVENT_ON_SUCCESS = 1;
+ static final int REPORT_EVENT_NO_RESPONSE = 1;
static final int REPORT_EVENT_UI_SHOWN = 2;
static final int REPORT_EVENT_UI_DESTROYED = 3;
@IntDef(prefix = { "REPORT_EVENT_" }, value = {
- REPORT_EVENT_ON_SUCCESS,
+ REPORT_EVENT_NO_RESPONSE,
REPORT_EVENT_UI_SHOWN,
REPORT_EVENT_UI_DESTROYED
})
@@ -319,6 +328,8 @@ public abstract class AugmentedAutofillService extends Service {
private final int mSessionId;
public final int taskId;
public final ComponentName componentName;
+ // Used for metrics / debug only
+ private String mServicePackageName;
@GuardedBy("mLock")
private AutofillId mFocusedId;
@GuardedBy("mLock")
@@ -349,6 +360,7 @@ public abstract class AugmentedAutofillService extends Service {
private CancellationSignal mCancellationSignal;
private AutofillProxy(int sessionId, @NonNull IBinder client, int taskId,
+ @NonNull ComponentName serviceComponentName,
@NonNull ComponentName componentName, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime,
@NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) {
@@ -357,6 +369,7 @@ public abstract class AugmentedAutofillService extends Service {
mCallback = callback;
this.taskId = taskId;
this.componentName = componentName;
+ mServicePackageName = serviceComponentName.getPackageName();
mFocusedId = focusedId;
mFocusedValue = focusedValue;
mFirstRequestTime = requestTime;
@@ -439,9 +452,9 @@ public abstract class AugmentedAutofillService extends Service {
mCallback.cancel();
}
} catch (RemoteException e) {
- Slog.e(TAG, "failed to check current pending request status", e);
+ Log.e(TAG, "failed to check current pending request status", e);
}
- Slog.d(TAG, "mCallback is updated.");
+ Log.d(TAG, "mCallback is updated.");
}
mCallback = callback;
}
@@ -463,13 +476,17 @@ public abstract class AugmentedAutofillService extends Service {
// Used (mostly) for metrics.
public void report(@ReportEvent int event) {
+ if (sVerbose) Log.v(TAG, "report(): " + event);
+ long duration = -1;
+ int type = MetricsEvent.TYPE_UNKNOWN;
switch (event) {
- case REPORT_EVENT_ON_SUCCESS:
+ case REPORT_EVENT_NO_RESPONSE:
+ type = MetricsEvent.TYPE_SUCCESS;
if (mFirstOnSuccessTime == 0) {
mFirstOnSuccessTime = SystemClock.elapsedRealtime();
+ duration = mFirstOnSuccessTime - mFirstRequestTime;
if (sDebug) {
- Slog.d(TAG, "Service responded in " + TimeUtils.formatDuration(
- mFirstOnSuccessTime - mFirstRequestTime));
+ Log.d(TAG, "Service responded nothing in " + formatDuration(duration));
}
}
try {
@@ -479,27 +496,25 @@ public abstract class AugmentedAutofillService extends Service {
}
break;
case REPORT_EVENT_UI_SHOWN:
+ type = MetricsEvent.TYPE_OPEN;
if (mUiFirstShownTime == 0) {
mUiFirstShownTime = SystemClock.elapsedRealtime();
- if (sDebug) {
- Slog.d(TAG, "UI shown in " + TimeUtils.formatDuration(
- mUiFirstShownTime - mFirstRequestTime));
- }
+ duration = mUiFirstShownTime - mFirstRequestTime;
+ if (sDebug) Log.d(TAG, "UI shown in " + formatDuration(duration));
}
break;
case REPORT_EVENT_UI_DESTROYED:
+ type = MetricsEvent.TYPE_CLOSE;
if (mUiFirstDestroyedTime == 0) {
mUiFirstDestroyedTime = SystemClock.elapsedRealtime();
- if (sDebug) {
- Slog.d(TAG, "UI destroyed in " + TimeUtils.formatDuration(
- mUiFirstDestroyedTime - mFirstRequestTime));
- }
+ duration = mUiFirstDestroyedTime - mFirstRequestTime;
+ if (sDebug) Log.d(TAG, "UI destroyed in " + formatDuration(duration));
}
break;
default:
- Slog.w(TAG, "invalid event reported: " + event);
+ Log.w(TAG, "invalid event reported: " + event);
}
- // TODO(b/122858578): log metrics as well
+ logResponse(type, mServicePackageName, componentName, mSessionId, duration);
}
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
@@ -527,19 +542,19 @@ public abstract class AugmentedAutofillService extends Service {
if (mFirstOnSuccessTime > 0) {
final long responseTime = mFirstOnSuccessTime - mFirstRequestTime;
pw.print(prefix); pw.print("response time: ");
- TimeUtils.formatDuration(responseTime, pw); pw.println();
+ formatDuration(responseTime, pw); pw.println();
}
if (mUiFirstShownTime > 0) {
final long uiRenderingTime = mUiFirstShownTime - mFirstRequestTime;
pw.print(prefix); pw.print("UI rendering time: ");
- TimeUtils.formatDuration(uiRenderingTime, pw); pw.println();
+ formatDuration(uiRenderingTime, pw); pw.println();
}
if (mUiFirstDestroyedTime > 0) {
final long uiTotalTime = mUiFirstDestroyedTime - mFirstRequestTime;
pw.print(prefix); pw.print("UI life time: ");
- TimeUtils.formatDuration(uiTotalTime, pw); pw.println();
+ formatDuration(uiTotalTime, pw); pw.println();
}
}
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 33e6a8c25ba4..0251386bd7ce 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -50,8 +50,10 @@ public final class FillCallback {
public void onSuccess(@Nullable FillResponse response) {
if (sDebug) Log.d(TAG, "onSuccess(): " + response);
- mProxy.report(AutofillProxy.REPORT_EVENT_ON_SUCCESS);
- if (response == null) return;
+ if (response == null) {
+ mProxy.report(AutofillProxy.REPORT_EVENT_NO_RESPONSE);
+ return;
+ }
final FillWindow fillWindow = response.getFillWindow();
if (fillWindow != null) {
diff --git a/core/java/android/service/autofill/augmented/Helper.java b/core/java/android/service/autofill/augmented/Helper.java
new file mode 100644
index 000000000000..501696f99c66
--- /dev/null
+++ b/core/java/android/service/autofill/augmented/Helper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.service.autofill.augmented;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.metrics.LogMaker;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/** @hide */
+public final class Helper {
+
+ private static final MetricsLogger sMetricsLogger = new MetricsLogger();
+
+ /**
+ * Logs a {@code MetricsEvent.AUTOFILL_AUGMENTED_RESPONSE} event.
+ */
+ public static void logResponse(int type, @NonNull String servicePackageName,
+ @NonNull ComponentName componentName, int mSessionId, long durationMs) {
+ final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_AUGMENTED_RESPONSE)
+ .setType(type)
+ .setComponentName(componentName)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, mSessionId)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, durationMs);
+ System.out.println("LOGGGO: " + log.getEntries()); // felipeal: tmp
+ sMetricsLogger.write(log);
+ }
+
+ private Helper() {
+ throw new UnsupportedOperationException("contains only static methods");
+ }
+}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 8819d220e748..0feab4d027a9 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1947,16 +1947,21 @@ public abstract class Transition implements Cloneable {
* @hide
*/
void forceToEnd(ViewGroup sceneRoot) {
- ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ final ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
int numOldAnims = runningAnimators.size();
- if (sceneRoot != null) {
- WindowId windowId = sceneRoot.getWindowId();
- for (int i = numOldAnims - 1; i >= 0; i--) {
- AnimationInfo info = runningAnimators.valueAt(i);
- if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
- Animator anim = runningAnimators.keyAt(i);
- anim.end();
- }
+ if (sceneRoot == null || numOldAnims == 0) {
+ return;
+ }
+
+ WindowId windowId = sceneRoot.getWindowId();
+ final ArrayMap<Animator, AnimationInfo> oldAnimators = new ArrayMap(runningAnimators);
+ runningAnimators.clear();
+
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ AnimationInfo info = oldAnimators.valueAt(i);
+ if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
+ Animator anim = oldAnimators.keyAt(i);
+ anim.end();
}
}
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index bbb90536e8f8..1812d291dd8f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,6 +33,7 @@ import android.graphics.Region;
import android.graphics.RenderNode;
import android.os.Build;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -119,11 +120,10 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
final Rect mScreenRect = new Rect();
SurfaceSession mSurfaceSession;
- SurfaceControl mSurfaceControl;
+ SurfaceControlWithBackground mSurfaceControl;
// In the case of format changes we switch out the surface in-place
// we need to preserve the old one until the new one has drawn.
- SurfaceControl mDeferredDestroySurfaceControl;
- SurfaceControl mBackgroundControl;
+ SurfaceControlWithBackground mDeferredDestroySurfaceControl;
final Rect mTmpRect = new Rect();
final Configuration mConfiguration = new Configuration();
@@ -487,29 +487,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
}
}
- private void updateBackgroundVisibilityInTransaction() {
- if (mBackgroundControl == null) {
- return;
- }
- if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
- mBackgroundControl.show();
- mBackgroundControl.setLayer(Integer.MIN_VALUE);
- } else {
- mBackgroundControl.hide();
- }
- }
-
- private void releaseSurfaces() {
- if (mSurfaceControl != null) {
- mSurfaceControl.remove();
- mSurfaceControl = null;
- }
- if (mBackgroundControl != null) {
- mBackgroundControl.remove();
- mBackgroundControl = null;
- }
- }
-
/** @hide */
protected void updateSurface() {
if (!mHaveFrame) {
@@ -576,21 +553,14 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
updateOpaqueFlag();
final String name = "SurfaceView - " + viewRoot.getTitle().toString();
- mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
- .setName(name)
- .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
- .setBufferSize(mSurfaceWidth, mSurfaceHeight)
- .setFormat(mFormat)
- .setParent(viewRoot.getSurfaceControl())
- .setFlags(mSurfaceFlags)
- .build();
- mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
- .setName("Background for -" + name)
- .setOpaque(true)
- .setColorLayer()
- .setParent(mSurfaceControl)
- .build();
-
+ mSurfaceControl = new SurfaceControlWithBackground(
+ name,
+ (mSurfaceFlags & SurfaceControl.OPAQUE) != 0,
+ new SurfaceControl.Builder(mSurfaceSession)
+ .setBufferSize(mSurfaceWidth, mSurfaceHeight)
+ .setFormat(mFormat)
+ .setParent(viewRoot.getSurfaceControl())
+ .setFlags(mSurfaceFlags));
} else if (mSurfaceControl == null) {
return;
}
@@ -607,13 +577,11 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
SurfaceControl.openTransaction();
try {
mSurfaceControl.setLayer(mSubLayer);
-
if (mViewVisibility) {
mSurfaceControl.show();
} else {
mSurfaceControl.hide();
}
- updateBackgroundVisibilityInTransaction();
// While creating the surface, we will set it's initial
// geometry. Outside of that though, we should generally
@@ -699,7 +667,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
}
if (creating) {
- mSurface.copyFrom(mSurfaceControl);
+ mSurface.copyFrom(mSurfaceControl.mForegroundControl);
}
if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
@@ -709,7 +677,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
// existing {@link Surface} will be ignored when the size changes.
// Therefore, we must explicitly recreate the {@link Surface} in these
// cases.
- mSurface.createFrom(mSurfaceControl);
+ mSurface.createFrom(mSurfaceControl.mForegroundControl);
}
if (visible && mSurface.isValid()) {
@@ -756,7 +724,8 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (mSurfaceControl != null && !mSurfaceCreated) {
mSurface.release();
- releaseSurfaces();
+ mSurfaceControl.remove();
+ mSurfaceControl = null;
}
}
} catch (Exception ex) {
@@ -857,7 +826,8 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
private void setParentSpaceRectangle(Rect position, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
- applySurfaceTransforms(mSurfaceControl, position, frameNumber);
+ applySurfaceTransforms(mSurfaceControl.mForegroundControl, position, frameNumber);
+ applySurfaceTransforms(mSurfaceControl.mBackgroundControl, position, frameNumber);
applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
frameNumber);
@@ -922,10 +892,13 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (frameNumber > 0) {
final ViewRootImpl viewRoot = getViewRootImpl();
- mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface,
+ mRtTransaction.deferTransactionUntilSurface(mSurfaceControl.mForegroundControl, viewRoot.mSurface,
+ frameNumber);
+ mRtTransaction.deferTransactionUntilSurface(mSurfaceControl.mBackgroundControl, viewRoot.mSurface,
frameNumber);
}
- mRtTransaction.hide(mSurfaceControl);
+ mRtTransaction.hide(mSurfaceControl.mForegroundControl);
+ mRtTransaction.hide(mSurfaceControl.mBackgroundControl);
mRtTransaction.apply();
}
};
@@ -972,19 +945,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
* @hide
*/
public void setResizeBackgroundColor(int bgColor) {
- if (mBackgroundControl == null) {
- return;
- }
-
- final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
- Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
-
- SurfaceControl.openTransaction();
- try {
- mBackgroundControl.setColor(colorComponents);
- } finally {
- SurfaceControl.closeTransaction();
- }
+ mSurfaceControl.setBackgroundColor(bgColor);
}
@UnsupportedAppUsage
@@ -1168,6 +1129,134 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
* @return The SurfaceControl for this SurfaceView.
*/
public SurfaceControl getSurfaceControl() {
- return mSurfaceControl;
+ return mSurfaceControl.mForegroundControl;
+ }
+
+ class SurfaceControlWithBackground {
+ SurfaceControl mForegroundControl;
+ SurfaceControl mBackgroundControl;
+ private boolean mOpaque = true;
+ public boolean mVisible = false;
+
+ public SurfaceControlWithBackground(String name, boolean opaque, SurfaceControl.Builder b)
+ throws Exception {
+ mForegroundControl = b.setName(name).build();
+ mBackgroundControl = b.setName("Background for -" + name)
+ // Unset the buffer size of the background color layer.
+ .setBufferSize(0, 0)
+ .setColorLayer()
+ .build();
+
+ mOpaque = opaque;
+ }
+
+ public void setAlpha(float alpha) {
+ mForegroundControl.setAlpha(alpha);
+ mBackgroundControl.setAlpha(alpha);
+ }
+
+ public void setLayer(int zorder) {
+ mForegroundControl.setLayer(zorder);
+ // -3 is below all other child layers as SurfaceView never goes below -2
+ mBackgroundControl.setLayer(-3);
+ }
+
+ public void setPosition(float x, float y) {
+ mForegroundControl.setPosition(x, y);
+ mBackgroundControl.setPosition(x, y);
+ }
+
+ public void setBufferSize(int w, int h) {
+ mForegroundControl.setBufferSize(w, h);
+ // The background surface is a color layer so we do not set a size.
+ }
+
+ public void setWindowCrop(Rect crop) {
+ mForegroundControl.setWindowCrop(crop);
+ mBackgroundControl.setWindowCrop(crop);
+ }
+
+ public void setWindowCrop(int width, int height) {
+ mForegroundControl.setWindowCrop(width, height);
+ mBackgroundControl.setWindowCrop(width, height);
+ }
+
+ public void setLayerStack(int layerStack) {
+ mForegroundControl.setLayerStack(layerStack);
+ mBackgroundControl.setLayerStack(layerStack);
+ }
+
+ public void setOpaque(boolean isOpaque) {
+ mForegroundControl.setOpaque(isOpaque);
+ mOpaque = isOpaque;
+ updateBackgroundVisibility();
+ }
+
+ public void setSecure(boolean isSecure) {
+ mForegroundControl.setSecure(isSecure);
+ }
+
+ public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ mForegroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
+ mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
+ }
+
+ public void hide() {
+ mForegroundControl.hide();
+ mVisible = false;
+ updateBackgroundVisibility();
+ }
+
+ public void show() {
+ mForegroundControl.show();
+ mVisible = true;
+ updateBackgroundVisibility();
+ }
+
+ public void remove() {
+ mForegroundControl.remove();
+ mBackgroundControl.remove();
+ }
+
+ public void release() {
+ mForegroundControl.release();
+ mBackgroundControl.release();
+ }
+
+ public void setTransparentRegionHint(Region region) {
+ mForegroundControl.setTransparentRegionHint(region);
+ mBackgroundControl.setTransparentRegionHint(region);
+ }
+
+ public void deferTransactionUntil(IBinder handle, long frame) {
+ mForegroundControl.deferTransactionUntil(handle, frame);
+ mBackgroundControl.deferTransactionUntil(handle, frame);
+ }
+
+ public void deferTransactionUntil(Surface barrier, long frame) {
+ mForegroundControl.deferTransactionUntil(barrier, frame);
+ mBackgroundControl.deferTransactionUntil(barrier, frame);
+ }
+
+ /** Set the color to fill the background with. */
+ private void setBackgroundColor(int bgColor) {
+ final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
+ Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
+
+ SurfaceControl.openTransaction();
+ try {
+ mBackgroundControl.setColor(colorComponents);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
+ void updateBackgroundVisibility() {
+ if (mOpaque && mVisible) {
+ mBackgroundControl.show();
+ } else {
+ mBackgroundControl.hide();
+ }
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4463e13ca5ee..e8356752f807 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8271,6 +8271,7 @@ public final class ViewRootImpl implements ViewParent,
void changeCanvasOpacity(boolean opaque) {
Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
+ opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0);
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.setOpaque(opaque);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 9a34ffae2a2e..b7d838edadc5 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -202,6 +202,9 @@ public class ChooserActivity extends ResolverActivity {
private long mChooserShownTime;
protected boolean mIsSuccessfullySelected;
+ private long mQueriedTargetServicesTimeMs;
+ private long mQueriedSharingShortcutsTimeMs;
+
private ChooserListAdapter mChooserListAdapter;
private ChooserRowAdapter mChooserRowAdapter;
private int mChooserRowServiceSpacing;
@@ -273,6 +276,8 @@ public class ChooserActivity extends ResolverActivity {
sri.connection.destroy();
mServiceConnections.remove(sri.connection);
if (mServiceConnections.isEmpty()) {
+ logDirectShareTargetReceived(
+ MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
sendVoiceChoicesIfNeeded();
}
break;
@@ -283,6 +288,8 @@ public class ChooserActivity extends ResolverActivity {
}
unbindRemainingServices();
+ logDirectShareTargetReceived(
+ MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
sendVoiceChoicesIfNeeded();
mChooserListAdapter.completeServiceTargetLoading();
break;
@@ -305,6 +312,8 @@ public class ChooserActivity extends ResolverActivity {
break;
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
+ logDirectShareTargetReceived(
+ MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER);
sendVoiceChoicesIfNeeded();
break;
@@ -1155,6 +1164,8 @@ public class ChooserActivity extends ResolverActivity {
}
void queryTargetServices(ChooserListAdapter adapter) {
+ mQueriedTargetServicesTimeMs = System.currentTimeMillis();
+
final PackageManager pm = getPackageManager();
ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class);
int targetsToQuery = 0;
@@ -1281,6 +1292,7 @@ public class ChooserActivity extends ResolverActivity {
private void queryDirectShareTargets(
ChooserListAdapter adapter, boolean skipAppPredictionService) {
+ mQueriedSharingShortcutsTimeMs = System.currentTimeMillis();
if (!skipAppPredictionService) {
AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
if (appPredictor != null) {
@@ -1391,6 +1403,14 @@ public class ChooserActivity extends ResolverActivity {
// Do nothing. We'll send the voice stuff ourselves.
}
+ private void logDirectShareTargetReceived(int logCategory) {
+ final long queryTime =
+ logCategory == MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER
+ ? mQueriedSharingShortcutsTimeMs : mQueriedTargetServicesTimeMs;
+ final int apiLatency = (int) (System.currentTimeMillis() - queryTime);
+ getMetricsLogger().write(new LogMaker(logCategory).setSubtype(apiLatency));
+ }
+
void updateModelAndChooserCounts(TargetInfo info) {
if (info != null) {
sendClickToAppPredictor(info);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index d50a70ed62ef..31f7d6f51ff8 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1958,8 +1958,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
final boolean isFullscreen = config.windowConfiguration.getWindowingMode()
== WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
return isFullscreen && (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility())
- & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE)));
+ & View.SYSTEM_UI_FLAG_FULLSCREEN));
}
private void updateDecorCaptionStatus(Configuration config) {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 28c59db6b932..c5fc9b3628df 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -49,8 +49,8 @@ int ifc_disable(const char *ifname);
namespace android {
constexpr int MAXPACKETSIZE = 8 * 1024;
-// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
-constexpr int MAXCMDSIZE = 1024;
+// FrameworkListener limits the size of commands to 4096 bytes.
+constexpr int MAXCMDSIZE = 4096;
static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 72e3d3495e37..74ebb95b58c7 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -37,14 +37,14 @@ void setDriverPathAndSphalLibraries_native(JNIEnv* env, jobject clazz, jstring p
void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName,
jstring driverVersionName, jlong driverVersionCode,
- jlong driverBuildTime, jstring appPackageName) {
+ jlong driverBuildTime, jstring appPackageName, jint vulkanVersion) {
ScopedUtfChars driverPackageNameChars(env, driverPackageName);
ScopedUtfChars driverVersionNameChars(env, driverVersionName);
ScopedUtfChars appPackageNameChars(env, appPackageName);
android::GraphicsEnv::getInstance().setGpuStats(driverPackageNameChars.c_str(),
driverVersionNameChars.c_str(),
driverVersionCode, driverBuildTime,
- appPackageNameChars.c_str());
+ appPackageNameChars.c_str(), vulkanVersion);
}
void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring devOptIn,
@@ -88,7 +88,7 @@ void setDebugLayersGLES_native(JNIEnv* env, jobject clazz, jstring layers) {
const JNINativeMethod g_methods[] = {
{ "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPathAndSphalLibraries_native) },
- { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
+ { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;I)V", reinterpret_cast<void*>(setGpuStats_native) },
{ "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
diff --git a/core/proto/android/stats/connectivity/resolv_stats.proto b/core/proto/android/stats/connectivity/resolv_stats.proto
deleted file mode 100644
index 43eb67397fa5..000000000000
--- a/core/proto/android/stats/connectivity/resolv_stats.proto
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-syntax = "proto2";
-package android.stats.connectivity;
-import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
-
-enum EventType {
- EVENT_UNKNOWN = 0;
- EVENT_GETADDRINFO = 1;
- EVENT_GETHOSTBYNAME = 2;
- EVENT_GETHOSTBYADDR = 3;
- EVENT_RES_NSEND = 4;
-}
-
-enum PrivateDnsModes {
- OFF = 0;
- OPPORTUNISTIC = 1;
- STRICT = 2;
-}
-// The return value of the DNS resolver for each DNS lookups.
-// bionic/libc/include/netdb.h
-// system/netd/resolv/include/netd_resolv/resolv.h
-enum ReturnCode {
- RC_EAI_NO_ERROR = 0;
- RC_EAI_ADDRFAMILY = 1;
- RC_EAI_AGAIN = 2;
- RC_EAI_BADFLAGS = 3;
- RC_EAI_FAIL = 4;
- RC_EAI_FAMILY = 5;
- RC_EAI_MEMORY = 6;
- RC_EAI_NODATA = 7;
- RC_EAI_NONAME = 8;
- RC_EAI_SERVICE = 9;
- RC_EAI_SOCKTYPE = 10;
- RC_EAI_SYSTEM = 11;
- RC_EAI_BADHINTS = 12;
- RC_EAI_PROTOCOL = 13;
- RC_EAI_OVERFLOW = 14;
- RC_RESOLV_TIMEOUT = 255;
- RC_EAI_MAX = 256;
-}
-
-
-enum NsRcode {
- ns_r_noerror = 0; // No error occurred.
- ns_r_formerr = 1; // Format error.
- ns_r_servfail = 2; // Server failure.
- ns_r_nxdomain = 3; // Name error.
- ns_r_notimpl = 4; // Unimplemented.
- ns_r_refused = 5; // Operation refused.
- // these are for BIND_UPDATE
- ns_r_yxdomain = 6; // Name exists
- ns_r_yxrrset = 7; // RRset exists
- ns_r_nxrrset = 8; // RRset does not exist
- ns_r_notauth = 9; // Not authoritative for zone
- ns_r_notzone = 10; // Zone of record different from zone section
- ns_r_max = 11;
- // The following are EDNS extended rcodes
- ns_r_badvers = 16;
- // The following are TSIG errors
- //ns_r_badsig = 16,
- ns_r_badkey = 17;
- ns_r_badtime = 18;
-}
-
-// Currently defined type values for resources and queries.
-enum NsType {
- ns_t_invalid = 0; // Cookie.
- ns_t_a = 1; // Host address.
- ns_t_ns = 2; // Authoritative server.
- ns_t_md = 3; // Mail destination.
- ns_t_mf = 4; // Mail forwarder.
- ns_t_cname = 5; // Canonical name.
- ns_t_soa = 6; // Start of authority zone.
- ns_t_mb = 7; // Mailbox domain name.
- ns_t_mg = 8; // Mail group member.
- ns_t_mr = 9; // Mail rename name.
- ns_t_null = 10; // Null resource record.
- ns_t_wks = 11; // Well known service.
- ns_t_ptr = 12; // Domain name pointer.
- ns_t_hinfo = 13; // Host information.
- ns_t_minfo = 14; // Mailbox information.
- ns_t_mx = 15; // Mail routing information.
- ns_t_txt = 16; // Text strings.
- ns_t_rp = 17; // Responsible person.
- ns_t_afsdb = 18; // AFS cell database.
- ns_t_x25 = 19; // X_25 calling address.
- ns_t_isdn = 20; // ISDN calling address.
- ns_t_rt = 21; // Router.
- ns_t_nsap = 22; // NSAP address.
- ns_t_nsap_ptr = 23; // Reverse NSAP lookup (deprecated).
- ns_t_sig = 24; // Security signature.
- ns_t_key = 25; // Security key.
- ns_t_px = 26; // X.400 mail mapping.
- ns_t_gpos = 27; // Geographical position (withdrawn).
- ns_t_aaaa = 28; // IPv6 Address.
- ns_t_loc = 29; // Location Information.
- ns_t_nxt = 30; // Next domain (security).
- ns_t_eid = 31; // Endpoint identifier.
- ns_t_nimloc = 32; // Nimrod Locator.
- ns_t_srv = 33; // Server Selection.
- ns_t_atma = 34; // ATM Address
- ns_t_naptr = 35; // Naming Authority PoinTeR
- ns_t_kx = 36; // Key Exchange
- ns_t_cert = 37; // Certification record
- ns_t_a6 = 38; // IPv6 address (experimental)
- ns_t_dname = 39; // Non-terminal DNAME
- ns_t_sink = 40; // Kitchen sink (experimentatl)
- ns_t_opt = 41; // EDNS0 option (meta-RR)
- ns_t_apl = 42; // Address prefix list (RFC 3123)
- ns_t_ds = 43; // Delegation Signer
- ns_t_sshfp = 44; // SSH Fingerprint
- ns_t_ipseckey = 45; // IPSEC Key
- ns_t_rrsig = 46; // RRset Signature
- ns_t_nsec = 47; // Negative security
- ns_t_dnskey = 48; // DNS Key
- ns_t_dhcid = 49; // Dynamic host configuratin identifier
- ns_t_nsec3 = 50; // Negative security type 3
- ns_t_nsec3param = 51;// Negative security type 3 parameters
- ns_t_hip = 55; // Host Identity Protocol
- ns_t_spf = 99; // Sender Policy Framework
- ns_t_tkey = 249; // Transaction key
- ns_t_tsig = 250; // Transaction signature.
- ns_t_ixfr = 251; // Incremental zone transfer.
- ns_t_axfr = 252; // Transfer zone of authority.
- ns_t_mailb = 253; // Transfer mailbox records.
- ns_t_maila = 254; // Transfer mail agent records.
- ns_t_any = 255; // Wildcard match.
- ns_t_zxfr = 256; // BIND-specific, nonstandard.
- ns_t_dlv = 32769; // DNSSEC look-aside validatation.
- ns_t_max = 65536;
-}
-
-enum IpVersion {
- IPV4 = 0;
- IPV6 = 1;
- MIXED = 2;
-}
-
-enum TransportType {
- UDP = 0;
- TCP = 1;
- DOT = 2;
- DOT_UDP = 3;
- DOT_TCP = 4;
-}
-
-message DnsQueryEvent {
- optional NsRcode rrcode = 1;
- optional NsType rrtype = 2;
- optional bool cache_hit = 3;
- optional IpVersion ipversion = 4;
- optional TransportType transport = 5;
- optional int32 packet_retransmits = 6; // Used only by the UDP transport
- optional int32 reconnects = 7; // Used only by TCP and DOT
- optional int32 latency_micros = 8;
- optional int32 active_experiments = 9;
- optional android.net.NetworkCapabilitiesProto.Transport network_type = 10;
-}
-
-message DnsQueryEventRe {
- repeated DnsQueryEvent dns_query_event = 1;
-}
-
-
-message DnsCallEvent {
-
-}
-
diff --git a/core/proto/android/stats/dnsresolver/Android.bp b/core/proto/android/stats/dnsresolver/Android.bp
new file mode 100644
index 000000000000..0b5aa8677a6e
--- /dev/null
+++ b/core/proto/android/stats/dnsresolver/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 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.
+
+java_library_static {
+ name: "dnsresolverprotosnano",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ "dns_resolver.proto",
+ ],
+ sdk_version: "system_current",
+ no_framework_libs: true,
+}
diff --git a/core/proto/android/stats/dnsresolver/dns_resolver.proto b/core/proto/android/stats/dnsresolver/dns_resolver.proto
new file mode 100644
index 000000000000..af6fea017bef
--- /dev/null
+++ b/core/proto/android/stats/dnsresolver/dns_resolver.proto
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+syntax = "proto2";
+package android.stats.dnsresolver;
+
+enum EventType {
+ EVENT_UNKNOWN = 0;
+ EVENT_GETADDRINFO = 1;
+ EVENT_GETHOSTBYNAME = 2;
+ EVENT_GETHOSTBYADDR = 3;
+ EVENT_RES_NSEND = 4;
+}
+
+// The return value of the DNS resolver for each DNS lookups.
+// bionic/libc/include/netdb.h
+// system/netd/resolv/include/netd_resolv/resolv.h
+enum ReturnCode {
+ RC_EAI_NO_ERROR = 0;
+ RC_EAI_ADDRFAMILY = 1;
+ RC_EAI_AGAIN = 2;
+ RC_EAI_BADFLAGS = 3;
+ RC_EAI_FAIL = 4;
+ RC_EAI_FAMILY = 5;
+ RC_EAI_MEMORY = 6;
+ RC_EAI_NODATA = 7;
+ RC_EAI_NONAME = 8;
+ RC_EAI_SERVICE = 9;
+ RC_EAI_SOCKTYPE = 10;
+ RC_EAI_SYSTEM = 11;
+ RC_EAI_BADHINTS = 12;
+ RC_EAI_PROTOCOL = 13;
+ RC_EAI_OVERFLOW = 14;
+ RC_RESOLV_TIMEOUT = 255;
+ RC_EAI_MAX = 256;
+}
+
+enum NsRcode {
+ NS_R_NO_ERROR = 0; // No error occurred.
+ NS_R_FORMERR = 1; // Format error.
+ NS_R_SERVFAIL = 2; // Server failure.
+ NS_R_NXDOMAIN = 3; // Name error.
+ NS_R_NOTIMPL = 4; // Unimplemented.
+ NS_R_REFUSED = 5; // Operation refused.
+ // these are for BIND_UPDATE
+ NS_R_YXDOMAIN = 6; // Name exists
+ NS_R_YXRRSET = 7; // RRset exists
+ NS_R_NXRRSET = 8; // RRset does not exist
+ NS_R_NOTAUTH = 9; // Not authoritative for zone
+ NS_R_NOTZONE = 10; // Zone of record different from zone section
+ NS_R_MAX = 11;
+ // The following are EDNS extended rcodes
+ NS_R_BADVERS = 16;
+ // The following are TSIG errors
+ // NS_R_BADSIG = 16,
+ NS_R_BADKEY = 17;
+ NS_R_BADTIME = 18;
+}
+
+// Currently defined type values for resources and queries.
+enum NsType {
+ NS_T_INVALID = 0; // Cookie.
+ NS_T_A = 1; // Host address.
+ NS_T_NS = 2; // Authoritative server.
+ NS_T_MD = 3; // Mail destination.
+ NS_T_MF = 4; // Mail forwarder.
+ NS_T_CNAME = 5; // Canonical name.
+ NS_T_SOA = 6; // Start of authority zone.
+ NS_T_MB = 7; // Mailbox domain name.
+ NS_T_MG = 8; // Mail group member.
+ NS_T_MR = 9; // Mail rename name.
+ NS_T_NULL = 10; // Null resource record.
+ NS_T_WKS = 11; // Well known service.
+ NS_T_PTR = 12; // Domain name pointer.
+ NS_T_HINFO = 13; // Host information.
+ NS_T_MINFO = 14; // Mailbox information.
+ NS_T_MX = 15; // Mail routing information.
+ NS_T_TXT = 16; // Text strings.
+ NS_T_RP = 17; // Responsible person.
+ NS_T_AFSDB = 18; // AFS cell database.
+ NS_T_X25 = 19; // X_25 calling address.
+ NS_T_ISDN = 20; // ISDN calling address.
+ NS_T_RT = 21; // Router.
+ NS_T_NSAP = 22; // NSAP address.
+ NS_T_NSAP_PTR = 23; // Reverse NSAP lookup (deprecated).
+ NS_T_SIG = 24; // Security signature.
+ NS_T_KEY = 25; // Security key.
+ NS_T_PX = 26; // X.400 mail mapping.
+ NS_T_GPOS = 27; // Geographical position (withdrawn).
+ NS_T_AAAA = 28; // IPv6 Address.
+ NS_T_LOC = 29; // Location Information.
+ NS_T_NXT = 30; // Next domain (security).
+ NS_T_EID = 31; // Endpoint identifier.
+ NS_T_NIMLOC = 32; // Nimrod Locator.
+ NS_T_SRV = 33; // Server Selection.
+ NS_T_ATMA = 34; // ATM Address
+ NS_T_NAPTR = 35; // Naming Authority PoinTeR
+ NS_T_KX = 36; // Key Exchange
+ NS_T_CERT = 37; // Certification record
+ NS_T_A6 = 38; // IPv6 address (experimental)
+ NS_T_DNAME = 39; // Non-terminal DNAME
+ NS_T_SINK = 40; // Kitchen sink (experimentatl)
+ NS_T_OPT = 41; // EDNS0 option (meta-RR)
+ NS_T_APL = 42; // Address prefix list (RFC 3123)
+ NS_T_DS = 43; // Delegation Signer
+ NS_T_SSHFP = 44; // SSH Fingerprint
+ NS_T_IPSECKEY = 45; // IPSEC Key
+ NS_T_RRSIG = 46; // RRset Signature
+ NS_T_NSEC = 47; // Negative security
+ NS_T_DNSKEY = 48; // DNS Key
+ NS_T_DHCID = 49; // Dynamic host configuratin identifier
+ NS_T_NSEC3 = 50; // Negative security type 3
+ NS_T_NSEC3PARAM = 51; // Negative security type 3 parameters
+ NS_T_HIP = 55; // Host Identity Protocol
+ NS_T_SPF = 99; // Sender Policy Framework
+ NS_T_TKEY = 249; // Transaction key
+ NS_T_TSIG = 250; // Transaction signature.
+ NS_T_IXFR = 251; // Incremental zone transfer.
+ NS_T_AXFR = 252; // Transfer zone of authority.
+ NS_T_MAILB = 253; // Transfer mailbox records.
+ NS_T_MAILA = 254; // Transfer mail agent records.
+ NS_T_ANY = 255; // Wildcard match.
+ NS_T_ZXFR = 256; // BIND-specific, nonstandard.
+ NS_T_DLV = 32769; // DNSSEC look-aside validatation.
+ NS_T_MAX = 65536;
+}
+
+enum IpVersion {
+ IV_UNKNOWN = 0;
+ IV_IPV4 = 1;
+ IV_IPV6 = 2;
+}
+
+enum TransportType {
+ TT_UNKNOWN = 0;
+ TT_UDP = 1;
+ TT_TCP = 2;
+ TT_DOT = 3;
+}
+
+enum PrivateDnsModes {
+ PDM_UNKNOWN = 0;
+ PDM_OFF = 1;
+ PDM_OPPORTUNISTIC = 2;
+ PDM_STRICT = 3;
+}
+
+enum Transport {
+ // Indicates this network uses a Cellular transport.
+ TRANSPORT_DEFAULT = 0; // TRANSPORT_CELLULAR
+ // Indicates this network uses a Wi-Fi transport.
+ TRANSPORT_WIFI = 1;
+ // Indicates this network uses a Bluetooth transport.
+ TRANSPORT_BLUETOOTH = 2;
+ // Indicates this network uses an Ethernet transport.
+ TRANSPORT_ETHERNET = 3;
+ // Indicates this network uses a VPN transport.
+ TRANSPORT_VPN = 4;
+ // Indicates this network uses a Wi-Fi Aware transport.
+ TRANSPORT_WIFI_AWARE = 5;
+ // Indicates this network uses a LoWPAN transport.
+ TRANSPORT_LOWPAN = 6;
+}
+
+enum CacheStatus{
+ // the cache can't handle that kind of queries.
+ // or the answer buffer is too small.
+ CS_UNSUPPORTED = 0;
+ // the cache doesn't know about this query.
+ CS_NOTFOUND = 1;
+ // the cache found the answer.
+ CS_FOUND = 2;
+ // Don't do anything on cache.
+ CS_SKIP = 3;
+}
+
+message DnsQueryEvent {
+ optional android.stats.dnsresolver.NsRcode rcode = 1;
+
+ optional android.stats.dnsresolver.NsType type = 2;
+
+ optional android.stats.dnsresolver.CacheStatus cache_hit = 3;
+
+ optional android.stats.dnsresolver.IpVersion ip_version = 4;
+
+ optional android.stats.dnsresolver.TransportType transport = 5;
+
+ // Number of DNS query retry times
+ optional int32 retry_times = 6;
+
+ // Ordinal number of name server.
+ optional int32 dns_server_count = 7;
+
+ // Used only by TCP and DOT. True for new connections.
+ optional bool connected = 8;
+
+ optional int32 latency_micros = 9;
+}
+
+message DnsQueryEvents {
+ repeated DnsQueryEvent dns_query_event = 1;
+}
diff --git a/core/res/res/anim/resolver_close_anim.xml b/core/res/res/anim/resolver_close_anim.xml
new file mode 100644
index 000000000000..18a25e985943
--- /dev/null
+++ b/core/res/res/anim/resolver_close_anim.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator"
+ android:zAdjustment="top">
+
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="0"
+ android:toYDelta="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/resolver_launch_anim.xml b/core/res/res/anim/resolver_launch_anim.xml
new file mode 100644
index 000000000000..ebb3701316fa
--- /dev/null
+++ b/core/res/res/anim/resolver_launch_anim.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+
+<!-- Animation for when a dock window at the bottom of the screen is entering. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_decelerate_interpolator"
+ android:zAdjustment="top">
+
+ <translate android:fromYDelta="100%"
+ android:toYDelta="0"
+ android:startOffset="@android:integer/config_shortAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set> \ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ab6f29b19445..4c6ae812f1ee 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3699,7 +3699,7 @@
<item name="config_inCallNotificationVolume" format="float" type="dimen">.10</item>
<!-- URI for in call notification sound -->
- <string translatable="false" name="config_inCallNotificationSound">/system/media/audio/ui/InCallNotification.ogg</string>
+ <string translatable="false" name="config_inCallNotificationSound">/product/media/audio/ui/InCallNotification.ogg</string>
<!-- Default number of notifications from the same app before they are automatically grouped by the OS -->
<integer translatable="false" name="config_autoGroupAtCount">4</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dd0a6e605f60..b07e7ef0bd05 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1549,11 +1549,11 @@
<!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
<string name="face_acquired_tilt_too_extreme">Turn your head a little less.</string>
<!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
- <string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string>
+ <string name="face_acquired_roll_too_extreme">Turn your head a little less.</string>
<!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
- <string name="face_acquired_obscured">Clear the space between your head and the phone.</string>
+ <string name="face_acquired_obscured">Remove anything hiding your face.</string>
<!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] -->
- <string name="face_acquired_sensor_dirty">Please clean the camera.</string>
+ <string name="face_acquired_sensor_dirty">Clean the sensor at the top edge of the screen.</string>
<!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings -->
<string-array name="face_acquired_vendor">
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 18a019a3e144..29181c871d1b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3787,6 +3787,8 @@
<java-symbol type="dimen" name="chooser_direct_share_label_placeholder_max_width" />
<java-symbol type="layout" name="chooser_az_label_row" />
<java-symbol type="string" name="chooser_all_apps_button_label" />
-
+ <java-symbol type="anim" name="resolver_launch_anim" />
+ <java-symbol type="style" name="Animation.DeviceDefault.Activity.Resolver" />
+
<java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 08d6d0621cf4..8015a5d5fbdd 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1667,8 +1667,7 @@ easier.
<!-- Theme used for the intent picker activity. -->
<style name="Theme.DeviceDefault.ResolverCommon" parent="Theme.DeviceDefault.DayNight">
- <item name="windowEnterTransition">@empty</item>
- <item name="windowExitTransition">@empty</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Activity.Resolver</item>
<item name="windowIsTranslucent">true</item>
<item name="windowNoTitle">true</item>
<item name="windowBackground">@color/transparent</item>
@@ -1682,6 +1681,14 @@ easier.
<item name="navigationBarDividerColor">@color/chooser_row_divider</item>
</style>
+ <style name="Animation.DeviceDefault.Activity.Resolver" parent="Animation.DeviceDefault.Activity">
+ <item name="activityOpenEnterAnimation">@anim/resolver_launch_anim</item>
+ <item name="taskOpenEnterAnimation">@anim/resolver_launch_anim</item>
+ <!-- Handle close for profile switching -->
+ <item name="activityOpenExitAnimation">@anim/resolver_close_anim</item>
+ <item name="taskOpenExitAnimation">@anim/resolver_close_anim</item>
+ </style>
+
<style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
<item name="windowLightNavigationBar">true</item>
</style>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a71460270252..e76754582fe9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -622,7 +622,6 @@ public class SettingsBackupTest {
Settings.Secure.COMPLETED_CATEGORY_PREFIX,
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
Settings.Secure.CONTENT_CAPTURE_ENABLED,
- Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK,
Settings.Secure.DEFAULT_INPUT_METHOD,
Settings.Secure.DEVICE_PAIRED,
Settings.Secure.DIALER_DEFAULT_APPLICATION,
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index 267cb365748e..eec7be22c78b 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -177,6 +177,23 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
.contains(APP_OVERLAY_PACKAGE_NAME));
}
+ @Test
+ public void testAdbShellOMSInterface() throws Exception {
+ installPackage("OverlayHostTests_AppOverlayV1.apk");
+ assertTrue(shell("cmd overlay list " + DEVICE_TEST_PKG).contains(DEVICE_TEST_PKG));
+ assertTrue(shell("cmd overlay list " + DEVICE_TEST_PKG).contains(APP_OVERLAY_PACKAGE_NAME));
+ assertEquals("[ ] " + APP_OVERLAY_PACKAGE_NAME,
+ shell("cmd overlay list " + APP_OVERLAY_PACKAGE_NAME).trim());
+ assertEquals("STATE_DISABLED",
+ shell("cmd overlay dump state " + APP_OVERLAY_PACKAGE_NAME).trim());
+
+ setOverlayEnabled(APP_OVERLAY_PACKAGE_NAME, true);
+ assertEquals("[x] " + APP_OVERLAY_PACKAGE_NAME,
+ shell("cmd overlay list " + APP_OVERLAY_PACKAGE_NAME).trim());
+ assertEquals("STATE_ENABLED",
+ shell("cmd overlay dump state " + APP_OVERLAY_PACKAGE_NAME).trim());
+ }
+
private void delay() {
try {
Thread.sleep(1000);
@@ -195,20 +212,24 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
}
private void installConvertExistingInstantPackageToFull(String pkg) throws Exception {
- getDevice().executeShellCommand("cmd package install-existing --wait --full " + pkg);
+ shell("cmd package install-existing --wait --full " + pkg);
}
private void setPackageEnabled(String pkg, boolean enabled) throws Exception {
- getDevice().executeShellCommand("cmd package " + (enabled ? "enable " : "disable ") + pkg);
+ shell("cmd package " + (enabled ? "enable " : "disable ") + pkg);
delay();
}
private void setOverlayEnabled(String pkg, boolean enabled) throws Exception {
- getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
+ shell("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
delay();
}
private boolean overlayManagerContainsPackage(String pkg) throws Exception {
- return getDevice().executeShellCommand("cmd overlay list").contains(pkg);
+ return shell("cmd overlay list").contains(pkg);
+ }
+
+ private String shell(final String cmd) throws Exception {
+ return getDevice().executeShellCommand(cmd);
}
}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 77f756baa1f2..68c0a22b30c7 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -33,7 +33,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
-import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.os.Environment;
import android.os.FileUtils;
@@ -50,7 +49,6 @@ import android.util.Log;
import com.android.internal.database.SortCursor;
-import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -59,7 +57,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.LinkedBlockingQueue;
/**
* RingtoneManager provides access to ringtones, notification, and other types
@@ -927,11 +924,7 @@ public class RingtoneManager {
}
// Tell MediaScanner about the new file. Wait for it to assign a {@link Uri}.
- try (NewRingtoneScanner scanner = new NewRingtoneScanner(outFile)) {
- return scanner.take();
- } catch (InterruptedException e) {
- throw new IOException("Audio file failed to scan as a ringtone", e);
- }
+ return MediaStore.scanFile(mContext, outFile);
}
private static final String getExternalDirectoryForType(final int type) {
@@ -1109,53 +1102,6 @@ public class RingtoneManager {
}
/**
- * Creates a {@link android.media.MediaScannerConnection} to scan a ringtone file and add its
- * information to the internal database.
- *
- * It uses a {@link java.util.concurrent.LinkedBlockingQueue} so that the caller can block until
- * the scan is completed.
- */
- private class NewRingtoneScanner implements Closeable, MediaScannerConnectionClient {
- private MediaScannerConnection mMediaScannerConnection;
- private File mFile;
- private LinkedBlockingQueue<Uri> mQueue = new LinkedBlockingQueue<>(1);
-
- public NewRingtoneScanner(File file) {
- mFile = file;
- mMediaScannerConnection = new MediaScannerConnection(mContext, this);
- mMediaScannerConnection.connect();
- }
-
- @Override
- public void close() {
- mMediaScannerConnection.disconnect();
- }
-
- @Override
- public void onMediaScannerConnected() {
- mMediaScannerConnection.scanFile(mFile.getAbsolutePath(), null);
- }
-
- @Override
- public void onScanCompleted(String path, Uri uri) {
- if (uri == null) {
- // There was some issue with scanning. Delete the copied file so it is not oprhaned.
- mFile.delete();
- return;
- }
- try {
- mQueue.put(uri);
- } catch (InterruptedException e) {
- Log.e(TAG, "Unable to put new ringtone Uri in queue", e);
- }
- }
-
- public Uri take() throws InterruptedException {
- return mQueue.take();
- }
- }
-
- /**
* Attempts to create a context for the given user.
*
* @return created context, or null if package does not exist
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 3500475eeeda..55692437d8d5 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -891,11 +891,16 @@ public final class MediaController {
}
/**
- * Set the playback speed.
+ * Sets the playback speed. A value of {@code 1.0f} is the default playback value,
+ * and a negative value indicates reverse playback. {@code 0.0f} is not allowed.
*
* @param speed The playback speed
+ * @throws IllegalArgumentException if the {@code speed} is equal to zero.
*/
public void setPlaybackSpeed(float speed) {
+ if (speed == 0.0f) {
+ throw new IllegalArgumentException("speed must not be zero");
+ }
try {
mSessionBinder.setPlaybackSpeed(mContext.getPackageName(), mCbStub, speed);
} catch (RemoteException e) {
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index c577469477e0..cee869ba4808 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -1084,6 +1084,9 @@ public final class MediaSession {
* To update the new playback speed, create a new {@link PlaybackState} by using {@link
* PlaybackState.Builder#setState(int, long, float)}, and set it with
* {@link #setPlaybackState(PlaybackState)}.
+ * <p>
+ * A value of {@code 1.0f} is the default playback value, and a negative value indicates
+ * reverse playback. The {@code speed} will not be equal to zero.
*
* @param speed the playback speed
* @see #setPlaybackState(PlaybackState)
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index d420966079fe..348f01eaa004 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -65,19 +65,19 @@
<!-- user interface sound effects -->
<integer name="def_power_sounds_enabled">1</integer>
- <string name="def_low_battery_sound" translatable="false">/system/media/audio/ui/LowBattery.ogg</string>
+ <string name="def_low_battery_sound" translatable="false">/product/media/audio/ui/LowBattery.ogg</string>
<integer name="def_dock_sounds_enabled">0</integer>
<integer name="def_dock_sounds_enabled_when_accessibility">0</integer>
- <string name="def_desk_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
- <string name="def_desk_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
- <string name="def_car_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
- <string name="def_car_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+ <string name="def_desk_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string>
+ <string name="def_desk_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string>
+ <string name="def_car_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string>
+ <string name="def_car_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string>
<integer name="def_lockscreen_sounds_enabled">1</integer>
- <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
- <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
- <string name="def_trusted_sound" translatable="false">/system/media/audio/ui/Trusted.ogg</string>
- <string name="def_wireless_charging_started_sound" translatable="false">/system/media/audio/ui/WirelessChargingStarted.ogg</string>
- <string name="def_charging_started_sound" translatable="false">/system/media/audio/ui/ChargingStarted.ogg</string>
+ <string name="def_lock_sound" translatable="false">/product/media/audio/ui/Lock.ogg</string>
+ <string name="def_unlock_sound" translatable="false">/product/media/audio/ui/Unlock.ogg</string>
+ <string name="def_trusted_sound" translatable="false">/product/media/audio/ui/Trusted.ogg</string>
+ <string name="def_wireless_charging_started_sound" translatable="false">/product/media/audio/ui/WirelessChargingStarted.ogg</string>
+ <string name="def_charging_started_sound" translatable="false">/product/media/audio/ui/ChargingStarted.ogg</string>
<!-- sound trigger detection service default values -->
<integer name="def_max_sound_trigger_detection_service_ops_per_day" translatable="false">1000</integer>
diff --git a/packages/SystemUI/res-keyguard/drawable/analog_frame.xml b/packages/SystemUI/res-keyguard/drawable/analog_frame.xml
index a663ac826127..3196169df7cc 100644
--- a/packages/SystemUI/res-keyguard/drawable/analog_frame.xml
+++ b/packages/SystemUI/res-keyguard/drawable/analog_frame.xml
@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="250dp"
- android:width="250dp"
+ android:height="380dp"
+ android:width="380dp"
android:viewportHeight="380"
android:viewportWidth="380">
- <path android:fillColor="#000000" android:pathData="M190,190m0,2a2,2 0,1 1,0 -4a2,2 0,1 1,0 4"/>
+ <path android:fillColor="#000000" android:pathData="M190,190m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml
index c7b6d60b319f..a05b16aa0204 100644
--- a/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml
+++ b/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml
@@ -1,7 +1,4 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="250dp"
- android:width="250dp"
- android:viewportHeight="380"
- android:viewportWidth="380">
- <path android:fillColor="#777777" android:fillType="evenOdd" android:pathData="M203,190C203,185.398 200.608,181.354 197,179.044L197,58C197,54.134 193.866,51 190,51C186.134,51 183,54.134 183,58L183,179.043C179.392,181.354 177,185.397 177,190C177,197.18 182.82,203 190,203C197.18,203 203,197.18 203,190Z"/>
+<vector android:height="380dp" android:viewportHeight="380"
+ android:viewportWidth="380" android:width="380dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#777777" android:fillType="evenOdd" android:pathData="m200,190.047c0.018,-3.701 -1.978,-6.942 -4.959,-8.686l0.582,-123.337c0.013,-2.761 -2.215,-5.011 -4.976,-5.024 -2.761,-0.013 -5.01,2.215 -5.024,4.976L185.041,181.314c-2.997,1.715 -5.024,4.937 -5.041,8.639 -0.026,5.523 4.43,10.021 9.953,10.047 5.523,0.026 10.021,-4.43 10.047,-9.953z"/>
</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml
index 458275bec23a..1277b6281032 100644
--- a/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml
+++ b/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml
@@ -1,7 +1,4 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="250dp"
- android:width="250dp"
- android:viewportHeight="380"
- android:viewportWidth="380">
- <path android:fillColor="#FFFFFF" android:pathData="M192,182.252C195.45,183.14 198,186.272 198,190C198,194.418 194.418,198 190,198C185.582,198 182,194.418 182,190C182,186.272 184.55,183.14 188,182.252L188,10C188,8.895 188.895,8 190,8C191.105,8 192,8.895 192,10L192,182.252Z"/>
+<vector android:height="380dp" android:viewportHeight="380"
+ android:viewportWidth="380" android:width="380dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#aaaaaa" android:fillType="evenOdd" android:pathData="m191,184.083c2.838,0.476 5,2.944 5,5.917 0,3.314 -2.686,6 -6,6 -3.314,0 -6,-2.686 -6,-6 0,-2.973 2.162,-5.441 5,-5.917V9c0,-0.552 0.448,-1 1,-1 0.552,0 1,0.448 1,1z"/>
</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 3118ab77bf6f..1967dd1013f9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -48,16 +48,16 @@
android:id="@+id/default_clock_view_bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
+ android:layout_gravity="bottom|center_horizontal"
android:gravity="center_horizontal"
android:letterSpacing="0.03"
android:textColor="?attr/wallpaperTextColor"
android:singleLine="true"
- style="@style/widget_big_bold"
+ style="@style/widget_title_bold"
android:format12Hour="@string/keyguard_widget_12_hours_format"
android:format24Hour="@string/keyguard_widget_24_hours_format"
android:elegantTextHeight="false"
- android:visibility="gone"
+ android:visibility="invisible"
/>
</FrameLayout>
<include layout="@layout/keyguard_status_area"
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index ab48f1df2ec2..1c8e141a61f8 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -66,16 +66,16 @@
<item name="android:fontFeatureSettings">@*android:string/config_headlineFontFeatureSettings</item>
<item name="android:ellipsize">none</item>
</style>
- <style name="widget_big_bold">
+ <style name="widget_title_bold">
<item name="android:textStyle">bold</item>
- <item name="android:textSize">@dimen/widget_big_font_size</item>
- <item name="android:paddingBottom">@dimen/bottom_text_spacing_digital</item>
+ <item name="android:textSize">@dimen/widget_title_font_size</item>
+ <item name="android:paddingBottom">@dimen/widget_vertical_padding_clock</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:ellipsize">none</item>
</style>
<style name="widget_small_bold">
<item name="android:textStyle">bold</item>
- <item name="android:textSize">@dimen/widget_title_font_size</item>
+ <item name="android:textSize">@dimen/widget_small_font_size</item>
<item name="android:paddingBottom">@dimen/bottom_text_spacing_digital</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:ellipsize">none</item>
diff --git a/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml
new file mode 100644
index 000000000000..c471b38306d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportWidth="40"
+ android:viewportHeight="40">
+ <path
+ android:fillColor="#9AA0A6"
+ android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7266L16.2734 24.6666L20 20.94L23.7267 24.6666L24.6667 23.7266L20.94 20L24.6667 16.2733Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
new file mode 100644
index 000000000000..15f14d8af89b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportWidth="40"
+ android:viewportHeight="40">
+ <path
+ android:fillColor="#5F6368"
+ android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
new file mode 100644
index 000000000000..2b210064023b
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.statusbar.notification.stack.SectionHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_section_header_height"
+ android:focusable="true"
+ android:clickable="true"
+ >
+ <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
+ android:id="@+id/backgroundNormal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
+ android:id="@+id/backgroundDimmed"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:id="@+id/header_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/notification_section_header_padding_left"
+ android:text="@string/notification_section_header_gentle"
+ android:textSize="12sp"
+ android:textColor="@color/notification_section_header_label_color"
+ />
+ <ImageView
+ android:id="@+id/btn_clear_all"
+ android:layout_width="@dimen/notification_section_header_height"
+ android:layout_height="@dimen/notification_section_header_height"
+ android:layout_marginRight="4dp"
+ android:src="@drawable/status_bar_notification_section_header_clear_btn"
+ android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
+ />
+ </LinearLayout>
+
+ <com.android.systemui.statusbar.notification.FakeShadowView
+ android:id="@+id/fake_shadow"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</com.android.systemui.statusbar.notification.stack.SectionHeaderView>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 89d1a19737ee..07d81c037e21 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -49,6 +49,8 @@
<color name="notification_guts_header_text_color">@color/GM2_grey_200</color>
<color name="notification_guts_button_color">@color/GM2_blue_200</color>
+ <color name="notification_section_header_label_color">@color/GM2_grey_200</color>
+
<!-- The color of the background in the top part of QSCustomizer -->
<color name="qs_customize_background">@color/GM2_grey_900</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 32879c052063..2200cf0112ac 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -97,6 +97,8 @@
<color name="notification_alert_color">#FFF87B2B</color>
<color name="notification_guts_button_color">@color/GM2_blue_700</color>
+ <color name="notification_section_header_label_color">@color/GM2_grey_900</color>
+
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 70e4b0d7054b..0fa542c498bc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -695,6 +695,9 @@
<!-- The top padding of the clear all button -->
<dimen name="clear_all_padding_top">12dp</dimen>
+ <dimen name="notification_section_header_height">40dp</dimen>
+ <dimen name="notification_section_header_padding_left">16dp</dimen>
+
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
quick settings header -->
<dimen name="max_avatar_size">48dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index f75f255324a6..e97055f08e32 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -103,6 +103,12 @@
<item type="id" name="action_snooze_assistant_suggestion_1"/>
<item type="id" name="action_snooze"/>
+ <!-- Accessibility actions for bubbles. -->
+ <item type="id" name="action_move_top_left"/>
+ <item type="id" name="action_move_top_right"/>
+ <item type="id" name="action_move_bottom_left"/>
+ <item type="id" name="action_move_bottom_right"/>
+
<!-- For StatusIconContainer to tag its icon views -->
<item type="id" name="status_bar_view_state_tag" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dc35653e5f7d..6ba72b6b85ad 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1102,6 +1102,12 @@
<!-- The text for the manage notifications link. [CHAR LIMIT=40] -->
<string name="manage_notifications_text">Manage</string>
+ <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_gentle">Gentle notifications</string>
+
+ <!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] -->
+ <string name="accessibility_notification_section_header_gentle_clear_all">Clear all gentle notifications</string>
+
<!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
<string name="dnd_suppressing_shade_text">Notifications paused by Do Not Disturb</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index f2a961d0b681..21b3a0082319 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -76,6 +76,8 @@ public abstract class TaskStackChangeListener {
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
+
/**
* Checks that the current user matches the process. Since
* {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index d250acca32c5..814db19c56b7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -184,6 +184,11 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
@Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) throws RemoteException {
+ mHandler.obtainMessage(H.ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
+ }
+
+ @Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
throws RemoteException {
mHandler.obtainMessage(H.ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
@@ -214,6 +219,7 @@ public class TaskStackChangeListeners extends TaskStackListener {
private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 15;
private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 16;
private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 17;
+ private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
public H(Looper looper) {
@@ -343,6 +349,12 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
break;
}
+ case ON_BACK_PRESSED_ON_TASK_ROOT: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onBackPressedOnTaskRoot(
+ (RunningTaskInfo) msg.obj);
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 8d62bca00f0a..c15c7872b6f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -3,22 +3,20 @@ package com.android.keyguard;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Build;
-import android.transition.ChangeBounds;
import android.transition.Transition;
import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
+import android.transition.TransitionSet;
import android.transition.TransitionValues;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
-import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -52,6 +50,11 @@ public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
/**
+ * Animation fraction when text is transitioned to/from bold.
+ */
+ private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
+
+ /**
* Controller used to track StatusBar state to know when to show the big_clock_container.
*/
private final StatusBarStateController mStatusBarStateController;
@@ -71,10 +74,8 @@ public class KeyguardClockSwitch extends RelativeLayout {
*/
private final Transition mTransition;
- /**
- * Listener for layout transitions.
- */
- private final Transition.TransitionListener mTransitionListener;
+ private final ClockVisibilityTransition mClockTransition;
+ private final ClockVisibilityTransition mBoldClockTransition;
/**
* Optional/alternative clock injected via plugin.
@@ -156,8 +157,19 @@ public class KeyguardClockSwitch extends RelativeLayout {
mStatusBarState = mStatusBarStateController.getState();
mSysuiColorExtractor = colorExtractor;
mClockManager = clockManager;
- mTransition = new ClockBoundsTransition();
- mTransitionListener = new ClockBoundsTransitionListener();
+
+ mClockTransition = new ClockVisibilityTransition().setCutoff(
+ 1 - TO_BOLD_TRANSITION_FRACTION);
+ mClockTransition.addTarget(R.id.default_clock_view);
+ mBoldClockTransition = new ClockVisibilityTransition().setCutoff(
+ TO_BOLD_TRANSITION_FRACTION);
+ mBoldClockTransition.addTarget(R.id.default_clock_view_bold);
+ mTransition = new TransitionSet()
+ .setOrdering(TransitionSet.ORDERING_TOGETHER)
+ .addTransition(mClockTransition)
+ .addTransition(mBoldClockTransition)
+ .setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
}
/**
@@ -182,7 +194,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
mClockManager.addOnClockChangedListener(mClockChangedListener);
mStatusBarStateController.addCallback(mStateListener);
mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
- mTransition.addListener(mTransitionListener);
updateColors();
}
@@ -192,7 +203,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
mClockManager.removeOnClockChangedListener(mClockChangedListener);
mStatusBarStateController.removeCallback(mStateListener);
mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
- mTransition.removeListener(mTransitionListener);
setClockPlugin(null);
}
@@ -287,7 +297,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
public void setTextSize(int unit, float size) {
mClockView.setTextSize(unit, size);
- mClockViewBold.setTextSize(unit, size);
}
public void setFormat12Hour(CharSequence format) {
@@ -390,23 +399,46 @@ public class KeyguardClockSwitch extends RelativeLayout {
* Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
* these cases.
*/
- public void setKeyguardShowingHeader(boolean hasHeader) {
+ void setKeyguardShowingHeader(boolean hasHeader) {
if (mShowingHeader == hasHeader || hasCustomClock()) {
return;
}
mShowingHeader = hasHeader;
+ float smallFontSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.widget_small_font_size);
+ float bigFontSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.widget_big_font_size);
+ mClockTransition.setScale(smallFontSize / bigFontSize);
+ mBoldClockTransition.setScale(bigFontSize / smallFontSize);
+
TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition);
- int fontSize = mContext.getResources().getDimensionPixelSize(mShowingHeader
- ? R.dimen.widget_small_font_size : R.dimen.widget_big_font_size);
- int paddingBottom = mContext.getResources().getDimensionPixelSize(mShowingHeader
+ mClockView.setVisibility(hasHeader ? View.INVISIBLE : View.VISIBLE);
+ mClockViewBold.setVisibility(hasHeader ? View.VISIBLE : View.INVISIBLE);
+ int paddingBottom = mContext.getResources().getDimensionPixelSize(hasHeader
? R.dimen.widget_vertical_padding_clock : R.dimen.header_subtitle_padding);
- mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
- mClockViewBold.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(),
mClockView.getPaddingRight(), paddingBottom);
mClockViewBold.setPadding(mClockViewBold.getPaddingLeft(), mClockViewBold.getPaddingTop(),
mClockViewBold.getPaddingRight(), paddingBottom);
+
+ if (hasHeader) {
+ // After the transition, make the default clock GONE so that it doesn't make the
+ // KeyguardStatusView appear taller in KeyguardClockPositionAlgorithm and elsewhere.
+ mTransition.addListener(new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ super.onTransitionEnd(transition);
+ // Check that header is actually showing. I saw issues where this event was
+ // fired after the big clock transitioned back to visible, which causes the time
+ // to completely disappear.
+ if (mShowingHeader) {
+ mClockView.setVisibility(View.GONE);
+ }
+ transition.removeListener(this);
+ }
+ });
+ }
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
@@ -434,91 +466,114 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
/**
- * Special layout transition that scales the clock view as its bounds change, to make it look
- * like the text is shrinking.
+ * {@link Visibility} transformation that scales the view while it is disappearing/appearing and
+ * transitions suddenly at a cutoff fraction during the animation.
*/
- private class ClockBoundsTransition extends ChangeBounds {
+ private class ClockVisibilityTransition extends android.transition.Visibility {
+
+ private static final String PROPNAME_VISIBILITY = "systemui:keyguard:visibility";
+
+ private float mCutoff;
+ private float mScale;
/**
- * Animation fraction when text is transitioned to/from bold.
+ * Constructs a transition that switches between visible/invisible at a cutoff and scales in
+ * size while appearing/disappearing.
*/
- private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
-
- ClockBoundsTransition() {
- setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2);
- setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ ClockVisibilityTransition() {
+ setCutoff(1f);
+ setScale(1f);
}
- @Override
- public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
- TransitionValues endValues) {
- Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
- if (animator == null || startValues.view != mClockView) {
- return animator;
- }
+ /**
+ * Sets the transition point between visible/invisible.
+ *
+ * @param cutoff The fraction in [0, 1] when the view switches between visible/invisible.
+ * @return This transition object
+ */
+ public ClockVisibilityTransition setCutoff(float cutoff) {
+ mCutoff = cutoff;
+ return this;
+ }
- ValueAnimator boundsAnimator = null;
- if (animator instanceof AnimatorSet) {
- Animator first = ((AnimatorSet) animator).getChildAnimations().get(0);
- if (first instanceof ValueAnimator) {
- boundsAnimator = (ValueAnimator) first;
- }
- } else if (animator instanceof ValueAnimator) {
- boundsAnimator = (ValueAnimator) animator;
- }
+ /**
+ * Sets the scale factor applied while appearing/disappearing.
+ *
+ * @param scale Scale factor applied while appearing/disappearing. When factor is less than
+ * one, the view will shrink while disappearing. When it is greater than one,
+ * the view will expand while disappearing.
+ * @return This transition object
+ */
+ public ClockVisibilityTransition setScale(float scale) {
+ mScale = scale;
+ return this;
+ }
- if (boundsAnimator != null) {
- float bigFontSize = mContext.getResources()
- .getDimensionPixelSize(R.dimen.widget_big_font_size);
- float smallFontSize = mContext.getResources()
- .getDimensionPixelSize(R.dimen.widget_small_font_size);
- float startScale = mShowingHeader
- ? bigFontSize / smallFontSize : smallFontSize / bigFontSize;
- final int normalViewVisibility = mShowingHeader ? View.INVISIBLE : View.VISIBLE;
- final int boldViewVisibility = mShowingHeader ? View.VISIBLE : View.INVISIBLE;
- final float boldTransitionFraction = mShowingHeader ? TO_BOLD_TRANSITION_FRACTION :
- 1f - TO_BOLD_TRANSITION_FRACTION;
- boundsAnimator.addUpdateListener(animation -> {
- final float fraction = animation.getAnimatedFraction();
- if (fraction > boldTransitionFraction) {
- mClockView.setVisibility(normalViewVisibility);
- mClockViewBold.setVisibility(boldViewVisibility);
- }
- float scale = MathUtils.lerp(startScale, 1f /* stop */,
- animation.getAnimatedFraction());
- mClockView.setPivotX(mClockView.getWidth() / 2f);
- mClockViewBold.setPivotX(mClockViewBold.getWidth() / 2f);
- mClockView.setPivotY(0);
- mClockViewBold.setPivotY(0);
- mClockView.setScaleX(scale);
- mClockViewBold.setScaleX(scale);
- mClockView.setScaleY(scale);
- mClockViewBold.setScaleY(scale);
- });
- }
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ super.captureStartValues(transitionValues);
+ captureVisibility(transitionValues);
+ }
- return animator;
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ super.captureStartValues(transitionValues);
+ captureVisibility(transitionValues);
}
- }
- /**
- * Transition listener for layout transition that scales the clock view.
- */
- private class ClockBoundsTransitionListener extends TransitionListenerAdapter {
+ private void captureVisibility(TransitionValues transitionValues) {
+ transitionValues.values.put(PROPNAME_VISIBILITY,
+ transitionValues.view.getVisibility());
+ }
@Override
- public void onTransitionEnd(Transition transition) {
- mClockView.setVisibility(mShowingHeader ? View.INVISIBLE : View.VISIBLE);
- mClockViewBold.setVisibility(mShowingHeader ? View.VISIBLE : View.INVISIBLE);
- mClockView.setScaleX(1f);
- mClockViewBold.setScaleX(1f);
- mClockView.setScaleY(1f);
- mClockViewBold.setScaleY(1f);
+ public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+ TransitionValues endValues) {
+ final float cutoff = mCutoff;
+ final int startVisibility = View.INVISIBLE;
+ final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
+ final float startScale = mScale;
+ final float endScale = 1f;
+ return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
+ endScale);
}
@Override
- public void onTransitionCancel(Transition transition) {
- onTransitionEnd(transition);
+ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+ TransitionValues endValues) {
+ final float cutoff = 1f - mCutoff;
+ final int startVisibility = View.VISIBLE;
+ final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
+ final float startScale = 1f;
+ final float endScale = mScale;
+ return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
+ endScale);
+ }
+
+ private Animator createAnimator(View view, float cutoff, int startVisibility,
+ int endVisibility, float startScale, float endScale) {
+ view.setPivotY(view.getHeight() - view.getPaddingBottom());
+ view.setVisibility(startVisibility);
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.addUpdateListener(animation -> {
+ final float fraction = animation.getAnimatedFraction();
+ if (fraction > cutoff) {
+ view.setVisibility(endVisibility);
+ }
+ final float scale = MathUtils.lerp(startScale, endScale, fraction);
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ });
+ addListener(new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ view.setVisibility(endVisibility);
+ view.setScaleX(1f);
+ view.setScaleY(1f);
+ transition.removeListener(this);
+ }
+ });
+ return animator;
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index ae8bc528ab6a..050655c79ffc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -19,6 +19,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import android.app.Presentation;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
@@ -32,9 +33,11 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.util.InjectionInflationController;
-// TODO(multi-display): Support multiple external displays
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
@@ -49,6 +52,9 @@ public class KeyguardDisplayManager {
private final SparseArray<Presentation> mPresentations = new SparseArray<>();
+ private final NavigationBarController mNavBarController =
+ Dependency.get(NavigationBarController.class);
+
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
@@ -56,6 +62,7 @@ public class KeyguardDisplayManager {
public void onDisplayAdded(int displayId) {
final Display display = mDisplayService.getDisplay(displayId);
if (mShowing) {
+ updateNavigationBarVisibility(displayId, false /* navBarVisible */);
showPresentation(display);
}
}
@@ -192,11 +199,15 @@ public class KeyguardDisplayManager {
if (showing) {
final Display[] displays = mDisplayService.getDisplays();
for (Display display : displays) {
+ int displayId = display.getDisplayId();
+ updateNavigationBarVisibility(displayId, false /* navBarVisible */);
changed |= showPresentation(display);
}
} else {
changed = mPresentations.size() > 0;
for (int i = mPresentations.size() - 1; i >= 0; i--) {
+ int displayId = mPresentations.keyAt(i);
+ updateNavigationBarVisibility(displayId, true /* navBarVisible */);
mPresentations.valueAt(i).dismiss();
}
mPresentations.clear();
@@ -204,6 +215,25 @@ public class KeyguardDisplayManager {
return changed;
}
+ // TODO(b/127878649): this logic is from
+ // {@link StatusBarKeyguardViewManager#updateNavigationBarVisibility}. Try to revisit a long
+ // term solution in R.
+ private void updateNavigationBarVisibility(int displayId, boolean navBarVisible) {
+ // Leave this task to {@link StatusBarKeyguardViewManager}
+ if (displayId == DEFAULT_DISPLAY) return;
+
+ NavigationBarView navBarView = mNavBarController.getNavigationBarView(displayId);
+ // We may not have nav bar on a display.
+ if (navBarView == null) return;
+
+ if (navBarVisible) {
+ navBarView.getRootView().setVisibility(View.VISIBLE);
+ } else {
+ navBarView.getRootView().setVisibility(View.GONE);
+ }
+
+ }
+
private final static class KeyguardPresentation extends Presentation {
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
@@ -251,6 +281,15 @@ public class KeyguardDisplayManager {
LayoutInflater inflater = mInjectableInflater.injectable(
LayoutInflater.from(getContext()));
setContentView(inflater.inflate(R.layout.keyguard_presentation, null));
+
+ // Logic to make the lock screen fullscreen
+ getWindow().getDecorView().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ getWindow().setNavigationBarContrastEnforced(false);
+ getWindow().setNavigationBarColor(Color.TRANSPARENT);
+
mClock = findViewById(R.id.clock);
// Avoid screen burn in
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index 9a0b1906dd4a..a39d811c93ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -402,6 +402,12 @@ public class FaceDialogView extends BiometricDialogView {
} else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
mHandler.removeCallbacks(mErrorToIdleAnimationRunnable);
mIconController.startPulsing();
+ } else if (oldState == STATE_ERROR && newState == STATE_PENDING_CONFIRMATION) {
+ mHandler.removeCallbacks(mErrorToIdleAnimationRunnable);
+ mIconController.animateOnce(R.drawable.face_dialog_wink_from_dark);
+ } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATED) {
+ mHandler.removeCallbacks(mErrorToIdleAnimationRunnable);
+ mIconController.animateOnce(R.drawable.face_dialog_dark_to_checkmark);
} else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
mIconController.animateOnce(R.drawable.face_dialog_dark_to_error);
mHandler.postDelayed(mErrorToIdleAnimationRunnable, BiometricPrompt.HIDE_DIALOG_DELAY);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index cff03c9b4b9b..7d189b28aa5e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -719,6 +719,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleData.setExpanded(false);
}
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ if (mStackView != null && taskInfo.displayId == getExpandedDisplayId(mContext)) {
+ mBubbleData.setExpanded(false);
+ }
+ }
}
private static boolean shouldAutoBubbleMessages(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index d1bc9a91636c..123d73dc6432 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -45,6 +45,7 @@ import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -391,11 +392,34 @@ public class BubbleStackView extends FrameLayout {
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
+
+ // Custom actions.
+ AccessibilityAction moveTopLeft = new AccessibilityAction(R.id.action_move_top_left,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_top_left));
+ info.addAction(moveTopLeft);
+
+ AccessibilityAction moveTopRight = new AccessibilityAction(R.id.action_move_top_right,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_top_right));
+ info.addAction(moveTopRight);
+
+ AccessibilityAction moveBottomLeft = new AccessibilityAction(R.id.action_move_bottom_left,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_bottom_left));
+ info.addAction(moveBottomLeft);
+
+ AccessibilityAction moveBottomRight = new AccessibilityAction(R.id.action_move_bottom_right,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_bottom_right));
+ info.addAction(moveBottomRight);
+
+ // Default actions.
+ info.addAction(AccessibilityAction.ACTION_DISMISS);
if (mIsExpanded) {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
+ info.addAction(AccessibilityAction.ACTION_COLLAPSE);
} else {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ info.addAction(AccessibilityAction.ACTION_EXPAND);
}
}
@@ -404,16 +428,30 @@ public class BubbleStackView extends FrameLayout {
if (super.performAccessibilityActionInternal(action, arguments)) {
return true;
}
- switch (action) {
- case AccessibilityNodeInfo.ACTION_DISMISS:
- mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
- return true;
- case AccessibilityNodeInfo.ACTION_COLLAPSE:
- mBubbleData.setExpanded(false);
- return true;
- case AccessibilityNodeInfo.ACTION_EXPAND:
- mBubbleData.setExpanded(true);
- return true;
+ final RectF stackBounds = mStackAnimationController.getAllowableStackPositionRegion();
+
+ // R constants are not final so we cannot use switch-case here.
+ if (action == AccessibilityNodeInfo.ACTION_DISMISS) {
+ mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
+ return true;
+ } else if (action == AccessibilityNodeInfo.ACTION_COLLAPSE) {
+ mBubbleData.setExpanded(false);
+ return true;
+ } else if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
+ mBubbleData.setExpanded(true);
+ return true;
+ } else if (action == R.id.action_move_top_left) {
+ mStackAnimationController.springStack(stackBounds.left, stackBounds.top);
+ return true;
+ } else if (action == R.id.action_move_top_right) {
+ mStackAnimationController.springStack(stackBounds.right, stackBounds.top);
+ return true;
+ } else if (action == R.id.action_move_bottom_left) {
+ mStackAnimationController.springStack(stackBounds.left, stackBounds.bottom);
+ return true;
+ } else if (action == R.id.action_move_bottom_right) {
+ mStackAnimationController.springStack(stackBounds.right, stackBounds.bottom);
+ return true;
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 47f2cd40b5e1..bc249aedc605 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -175,11 +175,33 @@ public class StackAnimationController extends
/** Whether the stack is on the left side of the screen. */
public boolean isStackOnLeftSide() {
- if (mLayout != null) {
- return mStackPosition.x - mIndividualBubbleSize / 2 < mLayout.getWidth() / 2;
- } else {
+ if (mLayout == null) {
return false;
}
+ float stackCenter = mStackPosition.x + mIndividualBubbleSize / 2;
+ float screenCenter = mLayout.getWidth() / 2;
+ return stackCenter < screenCenter;
+ }
+
+ /**
+ * Fling stack to given corner, within allowable screen bounds.
+ * Note that we need new SpringForce instances per animation despite identical configs because
+ * SpringAnimation uses SpringForce's internal (changing) velocity while the animation runs.
+ */
+ public void springStack(float destinationX, float destinationY) {
+ springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_X,
+ new SpringForce()
+ .setStiffness(SPRING_AFTER_FLING_STIFFNESS)
+ .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO),
+ 0 /* startXVelocity */,
+ destinationX);
+
+ springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_Y,
+ new SpringForce()
+ .setStiffness(SPRING_AFTER_FLING_STIFFNESS)
+ .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO),
+ 0 /* startYVelocity */,
+ destinationY);
}
/**
@@ -352,6 +374,7 @@ public class StackAnimationController extends
float destinationY = Float.MIN_VALUE;
if (imeVisible) {
+ // Stack is lower than it should be and overlaps the now-visible IME.
if (mStackPosition.y > maxBubbleY && mPreImeY == Float.MIN_VALUE) {
mPreImeY = mStackPosition.y;
destinationY = maxBubbleY;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
index c83c74f69f90..95e497e6574c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
@@ -26,6 +26,9 @@ import java.util.ArrayList;
* example, provide information on the current touch state.
*/
public class ClassifierData {
+ private static final long MINIMUM_DT_NANOS = 16666666; // 60Hz
+ private static final long MINIMUM_DT_SMEAR_NANOS = 2500000; // 2.5ms
+
private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>();
private ArrayList<Stroke> mEndingStrokes = new ArrayList<>();
private final float mDpi;
@@ -34,7 +37,18 @@ public class ClassifierData {
mDpi = dpi;
}
- public void update(MotionEvent event) {
+ /** Returns true if the event should be considered, false otherwise. */
+ public boolean update(MotionEvent event) {
+ // We limit to 60hz sampling. Drop anything happening faster than that.
+ // Legacy code was created with an assumed sampling rate. As devices increase their
+ // sampling rate, this creates potentialy false positives.
+ if (event.getActionMasked() == MotionEvent.ACTION_MOVE
+ && mCurrentStrokes.size() != 0
+ && event.getEventTimeNano() - mCurrentStrokes.get(0).getLastEventTimeNano()
+ < MINIMUM_DT_NANOS - MINIMUM_DT_SMEAR_NANOS) {
+ return false;
+ }
+
mEndingStrokes.clear();
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
@@ -54,6 +68,8 @@ public class ClassifierData {
mEndingStrokes.add(getStroke(id));
}
}
+
+ return true;
}
public void cleanUp(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 0cc50cddbfc6..86dccb222875 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -151,7 +151,9 @@ public class HumanInteractionClassifier extends Classifier {
}
private void addTouchEvent(MotionEvent event) {
- mClassifierData.update(event);
+ if (!mClassifierData.update(event)) {
+ return;
+ }
for (StrokeClassifier c : mStrokeClassifiers) {
c.onTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
index fb04d3e73a2d..977a2d0b528a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
@@ -68,4 +68,12 @@ public class Stroke {
public ArrayList<Point> getPoints() {
return mPoints;
}
+
+ public long getLastEventTimeNano() {
+ if (mPoints.isEmpty()) {
+ return mStartTimeNano;
+ }
+
+ return mPoints.get(mPoints.size() - 1).timeOffsetNano;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index bd25209d5c0f..7bcbd3683130 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -32,6 +32,8 @@ import android.view.IWindowManager;
import android.view.View;
import android.view.WindowManagerGlobal;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.systemui.Dependency;
@@ -213,8 +215,17 @@ public class NavigationBarController implements Callbacks {
}
/** @return {@link NavigationBarView} on the default display. */
- public NavigationBarView getDefaultNavigationBarView() {
- NavigationBarFragment navBar = mNavigationBars.get(DEFAULT_DISPLAY);
+ public @Nullable NavigationBarView getDefaultNavigationBarView() {
+ return getNavigationBarView(DEFAULT_DISPLAY);
+ }
+
+ /**
+ * @param displayId the ID of display which Navigation bar is on
+ * @return {@link NavigationBarView} on the display with {@code displayId}.
+ * {@code null} if no navigation bar on that display.
+ */
+ public @Nullable NavigationBarView getNavigationBarView(int displayId) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
return (navBar == null) ? null : (NavigationBarView) navBar.getView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index 0a2e04fd9430..b732966b32db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -97,7 +97,6 @@ public class MessagingLayoutTransformState extends TransformState {
HashMap<MessagingGroup, MessagingGroup> pairs = findPairs(ownGroups, otherGroups);
MessagingGroup lastPairedGroup = null;
float currentTranslation = 0;
- float transformationDistanceRemaining = 0;
for (int i = ownGroups.size() - 1; i >= 0; i--) {
MessagingGroup ownGroup = ownGroups.get(i);
MessagingGroup matchingGroup = pairs.get(ownGroup);
@@ -108,13 +107,10 @@ public class MessagingLayoutTransformState extends TransformState {
lastPairedGroup = ownGroup;
if (to){
float totalTranslation = ownGroup.getTop() - matchingGroup.getTop();
- transformationDistanceRemaining
- = matchingGroup.getAvatar().getTranslationY();
- currentTranslation = transformationDistanceRemaining - totalTranslation;
+ currentTranslation = matchingGroup.getAvatar().getTranslationY()
+ - totalTranslation;
} else {
- float totalTranslation = matchingGroup.getTop() - ownGroup.getTop();
currentTranslation = ownGroup.getAvatar().getTranslationY();
- transformationDistanceRemaining = currentTranslation - totalTranslation;
}
}
} else {
@@ -122,14 +118,20 @@ public class MessagingLayoutTransformState extends TransformState {
if (lastPairedGroup != null) {
adaptGroupAppear(ownGroup, transformationAmount, currentTranslation,
to);
- int distance = lastPairedGroup.getTop() - ownGroup.getTop();
- float transformationDistance = mTransformInfo.isAnimating()
- ? distance
- : ownGroup.getHeight() * 0.75f;
- float translationProgress = transformationDistanceRemaining
- - (distance - transformationDistance);
- groupTransformationAmount =
- translationProgress / transformationDistance;
+ float newPosition = ownGroup.getTop() + currentTranslation;
+
+ if (!mTransformInfo.isAnimating()) {
+ // We fade the group away as soon as 1/2 of it is translated away on top
+ float fadeStart = -ownGroup.getHeight() * 0.5f;
+ groupTransformationAmount = (newPosition - fadeStart)
+ / Math.abs(fadeStart);
+ } else {
+ float fadeStart = -ownGroup.getHeight() * 0.75f;
+ // We want to fade out as soon as the animation starts, let's add the
+ // complete top in addition
+ groupTransformationAmount = (newPosition - fadeStart)
+ / (Math.abs(fadeStart) + ownGroup.getTop());
+ }
groupTransformationAmount = Math.max(0.0f, Math.min(1.0f,
groupTransformationAmount));
if (to) {
@@ -175,7 +177,8 @@ public class MessagingLayoutTransformState extends TransformState {
relativeOffset *= 0.5f;
}
ownGroup.getMessageContainer().setTranslationY(relativeOffset);
- ownGroup.setTranslationY(overallTranslation * 0.85f);
+ ownGroup.getSenderView().setTranslationY(relativeOffset);
+ ownGroup.setTranslationY(overallTranslation * 0.9f);
}
private void disappear(MessagingGroup ownGroup, float transformationAmount) {
@@ -256,6 +259,9 @@ public class MessagingLayoutTransformState extends TransformState {
float distanceToTop = child.getTop() + child.getHeight() + previousTranslation;
transformationAmount = distanceToTop / child.getHeight();
transformationAmount = Math.max(0.0f, Math.min(1.0f, transformationAmount));
+ if (to) {
+ transformationAmount = 1.0f - transformationAmount;
+ }
}
transformView(transformationAmount, to, child, otherChild, false, /* sameAsAny */
useLinearTransformation);
@@ -400,6 +406,7 @@ public class MessagingLayoutTransformState extends TransformState {
setClippingDeactivated(ownGroup.getSenderView(), false);
ownGroup.setTranslationY(0);
ownGroup.getMessageContainer().setTranslationY(0);
+ ownGroup.getSenderView().setTranslationY(0);
}
ownGroup.setTransformingImages(false);
ownGroup.updateClipRect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index f9a98ad297f5..91c43a142db5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -206,7 +206,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
long actions = mMediaController.getPlaybackState().getActions();
Log.d(TAG, "Playback state actions are " + actions);
- return (actions == 0 || (actions & PlaybackState.ACTION_SEEK_TO) != 0);
+ return ((actions & PlaybackState.ACTION_SEEK_TO) != 0);
}
protected final Runnable mUpdatePlaybackUi = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ce922801551b..8c6d1015bd4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.util.MathUtils;
@@ -30,18 +31,18 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
import java.util.ArrayList;
-import java.util.List;
/**
* A global state to track all input states for the algorithm.
*/
public class AmbientState {
- private static final int NO_SECTION_BOUNDARY = -1;
private static final float MAX_PULSE_HEIGHT = 100000f;
+ private final SectionProvider mSectionProvider;
private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
private int mScrollY;
private int mAnchorViewIndex;
@@ -51,7 +52,6 @@ public class AmbientState {
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
private int mSpeedBumpIndex = -1;
- private final List<Integer> mSectionBoundaryIndices = new ArrayList<>();
private boolean mDark;
private boolean mHideSensitive;
private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
@@ -84,8 +84,10 @@ public class AmbientState {
private float mPulseHeight = MAX_PULSE_HEIGHT;
private float mDozeAmount = 0.0f;
- public AmbientState(Context context) {
- mSectionBoundaryIndices.add(NO_SECTION_BOUNDARY);
+ public AmbientState(
+ Context context,
+ @NonNull SectionProvider sectionProvider) {
+ mSectionProvider = sectionProvider;
reload(context);
}
@@ -245,25 +247,8 @@ public class AmbientState {
mSpeedBumpIndex = shelfIndex;
}
- /**
- * Returns the index of the boundary between two sections, where the first section is at index
- * {@code boundaryNum}.
- */
- public int getSectionBoundaryIndex(int boundaryNum) {
- return mSectionBoundaryIndices.get(boundaryNum);
- }
-
- /** Returns true if the item at {@code index} is directly below a section boundary. */
- public boolean beginsNewSection(int index) {
- return mSectionBoundaryIndices.contains(index);
- }
-
- /**
- * Sets the index of the boundary between the section at {@code boundaryNum} and the following
- * section to {@code boundaryIndex}.
- */
- public void setSectionBoundaryIndex(int boundaryNum, int boundaryIndex) {
- mSectionBoundaryIndices.set(boundaryNum, boundaryIndex);
+ public SectionProvider getSectionProvider() {
+ return mSectionProvider;
}
public float getStackTranslation() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
new file mode 100644
index 000000000000..82599f02ddf1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.notification.stack;
+
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
+/**
+ * Manages the boundaries of the two notification sections (high priority and low priority). Also
+ * shows/hides the headers for those sections where appropriate.
+ *
+ * TODO: Move remaining sections logic from NSSL into this class.
+ */
+class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvider {
+ private final NotificationStackScrollLayout mParent;
+ private final ActivityStarter mActivityStarter;
+ private final boolean mUseMultipleSections;
+
+ private SectionHeaderView mGentleHeader;
+ private boolean mGentleHeaderVisible = false;
+ @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
+
+ NotificationSectionsManager(
+ NotificationStackScrollLayout parent,
+ ActivityStarter activityStarter,
+ boolean useMultipleSections) {
+ mParent = parent;
+ mActivityStarter = activityStarter;
+ mUseMultipleSections = useMultipleSections;
+ }
+
+ /**
+ * Must be called before use. Should be called again whenever inflation-related things change,
+ * such as density or theme changes.
+ */
+ void inflateViews(Context context) {
+ int oldPos = -1;
+ if (mGentleHeader != null) {
+ if (mGentleHeader.getTransientContainer() != null) {
+ mGentleHeader.getTransientContainer().removeView(mGentleHeader);
+ } else if (mGentleHeader.getParent() != null) {
+ oldPos = mParent.indexOfChild(mGentleHeader);
+ mParent.removeView(mGentleHeader);
+ }
+ }
+
+ mGentleHeader = (SectionHeaderView) LayoutInflater.from(context).inflate(
+ R.layout.status_bar_notification_section_header, mParent, false);
+ mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
+ mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick);
+
+ if (oldPos != -1) {
+ mParent.addView(mGentleHeader, oldPos);
+ }
+ }
+
+ /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */
+ void setOnClearGentleNotifsClickListener(View.OnClickListener listener) {
+ mOnClearGentleNotifsClickListener = listener;
+ }
+
+ /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
+ void onUiModeChanged() {
+ mGentleHeader.onUiModeChanged();
+ }
+
+ @Override
+ public boolean beginsSection(View view) {
+ return view == mGentleHeader;
+ }
+
+ /**
+ * Should be called whenever notifs are added, removed, or updated. Updates section boundary
+ * bookkeeping and adds/moves/removes section headers if appropriate.
+ */
+ void updateSectionBoundaries() {
+ if (!mUseMultipleSections) {
+ return;
+ }
+
+ int firstGentleNotifIndex = -1;
+
+ final int n = mParent.getChildCount();
+ for (int i = 0; i < n; i++) {
+ View child = mParent.getChildAt(i);
+ if (child instanceof ExpandableNotificationRow
+ && child.getVisibility() != View.GONE) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (!row.getEntry().isHighPriority()) {
+ firstGentleNotifIndex = i;
+ break;
+ }
+ }
+ }
+
+ adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex);
+
+ mGentleHeader.setAreThereDismissableGentleNotifs(
+ mParent.hasActiveClearableNotifications(ROWS_GENTLE));
+ }
+
+ private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) {
+ final int currentHeaderIndex = mParent.indexOfChild(mGentleHeader);
+
+ if (firstGentleNotifIndex == -1) {
+ if (mGentleHeaderVisible) {
+ mGentleHeaderVisible = false;
+ mParent.removeView(mGentleHeader);
+ }
+ } else {
+ if (!mGentleHeaderVisible) {
+ mGentleHeaderVisible = true;
+ // If the header is animating away, it will still have a parent, so detach it first
+ // TODO: We should really cancel the active animations here. This will happen
+ // automatically when the view's intro animation starts, but it's a fragile link.
+ if (mGentleHeader.getTransientContainer() != null) {
+ mGentleHeader.getTransientContainer().removeTransientView(mGentleHeader);
+ mGentleHeader.setTransientContainer(null);
+ }
+ mParent.addView(mGentleHeader, firstGentleNotifIndex);
+ } else if (currentHeaderIndex != firstGentleNotifIndex - 1) {
+ // Relocate the header to be immediately before the first child in the section
+ int targetIndex = firstGentleNotifIndex;
+ if (currentHeaderIndex < firstGentleNotifIndex) {
+ // Adjust the target index to account for the header itself being temporarily
+ // removed during the position change.
+ targetIndex--;
+ }
+
+ mParent.changeViewPosition(mGentleHeader, targetIndex);
+ }
+ }
+ }
+
+ /**
+ * Updates the boundaries (as tracked by their first and last views) of the high and low
+ * priority sections.
+ *
+ * @return {@code true} If the last view in the top section changed (so we need to animate).
+ */
+ boolean updateFirstAndLastViewsInSections(
+ final NotificationSection highPrioritySection,
+ final NotificationSection lowPrioritySection,
+ ActivatableNotificationView firstChild,
+ ActivatableNotificationView lastChild) {
+ if (mUseMultipleSections) {
+ ActivatableNotificationView previousLastHighPriorityChild =
+ highPrioritySection.getLastVisibleChild();
+ ActivatableNotificationView previousFirstLowPriorityChild =
+ lowPrioritySection.getFirstVisibleChild();
+ ActivatableNotificationView lastHighPriorityChild = getLastHighPriorityChild();
+ ActivatableNotificationView firstLowPriorityChild = getFirstLowPriorityChild();
+ if (lastHighPriorityChild != null && firstLowPriorityChild != null) {
+ highPrioritySection.setFirstVisibleChild(firstChild);
+ highPrioritySection.setLastVisibleChild(lastHighPriorityChild);
+ lowPrioritySection.setFirstVisibleChild(firstLowPriorityChild);
+ lowPrioritySection.setLastVisibleChild(lastChild);
+ } else if (lastHighPriorityChild != null) {
+ highPrioritySection.setFirstVisibleChild(firstChild);
+ highPrioritySection.setLastVisibleChild(lastChild);
+ lowPrioritySection.setFirstVisibleChild(null);
+ lowPrioritySection.setLastVisibleChild(null);
+ } else {
+ highPrioritySection.setFirstVisibleChild(null);
+ highPrioritySection.setLastVisibleChild(null);
+ lowPrioritySection.setFirstVisibleChild(firstChild);
+ lowPrioritySection.setLastVisibleChild(lastChild);
+ }
+ return lastHighPriorityChild != previousLastHighPriorityChild
+ || firstLowPriorityChild != previousFirstLowPriorityChild;
+ } else {
+ highPrioritySection.setFirstVisibleChild(firstChild);
+ highPrioritySection.setLastVisibleChild(lastChild);
+ return false;
+ }
+ }
+
+ @VisibleForTesting
+ SectionHeaderView getGentleHeaderView() {
+ return mGentleHeader;
+ }
+
+ @Nullable
+ private ActivatableNotificationView getFirstLowPriorityChild() {
+ return mGentleHeaderVisible ? mGentleHeader : null;
+ }
+
+ @Nullable
+ private ActivatableNotificationView getLastHighPriorityChild() {
+ ActivatableNotificationView lastChildBeforeGap = null;
+ int childCount = mParent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = mParent.getChildAt(i);
+ if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (!row.getEntry().isHighPriority()) {
+ break;
+ } else {
+ lastChildBeforeGap = row;
+ }
+ }
+ }
+ return lastChildBeforeGap;
+ }
+
+ private void onGentleHeaderClick(View v) {
+ Intent intent = new Intent(Settings.ACTION_NOTIFICATION_SETTINGS);
+ mActivityStarter.startActivity(
+ intent,
+ true,
+ true,
+ Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ }
+
+ private void onClearGentleNotifsClick(View v) {
+ if (mOnClearGentleNotifsClickListener != null) {
+ mOnClearGentleNotifsClickListener.onClick(v);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 642e2e483d89..5bd6cab1809b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -23,10 +23,13 @@ import static com.android.systemui.statusbar.notification.stack.StackStateAnimat
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.LOW_PRIORITY;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperManager;
@@ -87,6 +90,7 @@ import com.android.systemui.SwipeHelper;
import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.classifier.FalsingManagerFactory.FalsingManager;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
@@ -142,6 +146,7 @@ import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -498,6 +503,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private final NotificationGutsManager
mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+ private final NotificationSectionsManager mSectionsManager;
/**
* If the {@link NotificationShelf} should be visible when dark.
*/
@@ -511,7 +517,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
NotificationRoundnessManager notificationRoundnessManager,
AmbientPulseManager ambientPulseManager,
- DynamicPrivacyController dynamicPrivacyController) {
+ DynamicPrivacyController dynamicPrivacyController,
+ ActivityStarter activityStarter) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -522,7 +529,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
mAmbientPulseManager = ambientPulseManager;
- mAmbientState = new AmbientState(context);
+
+ mSectionsManager =
+ new NotificationSectionsManager(
+ this,
+ activityStarter,
+ NotificationUtils.useNewInterruptionModel(context));
+ mSectionsManager.inflateViews(context);
+ mSectionsManager.setOnClearGentleNotifsClickListener(v -> {
+ // Leave the shade open if there will be other notifs left over to clear
+ final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY);
+ clearNotifications(ROWS_GENTLE, closeShade);
+ });
+
+ mAmbientState = new AmbientState(context, mSectionsManager);
mRoundnessManager = notificationRoundnessManager;
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
@@ -629,6 +649,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
inflateFooterView();
inflateEmptyShadeView();
updateFooter();
+ mSectionsManager.inflateViews(mContext);
}
@Override
@@ -662,7 +683,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
- boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
+ boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
boolean showFooterView = (showDismissView ||
mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
&& mStatusBarState != StatusBarState.KEYGUARD
@@ -675,14 +696,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* Return whether there are any clearable notifications
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public boolean hasActiveClearableNotifications() {
+ public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (!(child instanceof ExpandableNotificationRow)) {
continue;
}
- if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (row.canViewBeDismissed() && matchesSelection(row, selection)) {
return true;
}
}
@@ -739,6 +761,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
updateBackgroundDimming();
mShelf.onUiModeChanged();
+ mSectionsManager.onUiModeChanged();
}
@ShadeViewRefactor(RefactorComponent.DECORATOR)
@@ -1684,11 +1707,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return mScrollingEnabled;
}
- @ShadeViewRefactor(RefactorComponent.ADAPTER)
- private boolean canChildBeDismissed(View v) {
- return StackScrollAlgorithm.canChildBeDismissed(v);
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
@@ -2580,41 +2598,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return null;
}
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- @Nullable
- private ActivatableNotificationView getLastHighPriorityChild() {
- ActivatableNotificationView lastChildBeforeGap = null;
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.getEntry().isHighPriority()) {
- break;
- } else {
- lastChildBeforeGap = row;
- }
- }
- }
- return lastChildBeforeGap;
- }
-
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- @Nullable
- private ActivatableNotificationView getFirstLowPriorityChild() {
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.getEntry().isHighPriority()) {
- return row;
- }
- }
- }
- return null;
- }
-
/**
* Fling the scroll view
*
@@ -3180,7 +3163,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
ActivatableNotificationView firstChild = getFirstChildWithBackground();
ActivatableNotificationView lastChild = getLastChildWithBackground();
- boolean sectionViewsChanged = updateFirstAndLastViewsInSectionsByPriority(
+ boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsInSections(
mSections[0], mSections[1], firstChild, lastChild);
if (mAnimationsEnabled && mIsExpanded) {
@@ -3198,44 +3181,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
invalidate();
}
- /** @return {@code true} if the last view in the top section changed (so we need to animate). */
- private boolean updateFirstAndLastViewsInSectionsByPriority(
- final NotificationSection highPrioritySection,
- final NotificationSection lowPrioritySection,
- ActivatableNotificationView firstChild,
- ActivatableNotificationView lastChild) {
- if (NotificationUtils.useNewInterruptionModel(mContext)) {
- ActivatableNotificationView previousLastHighPriorityChild =
- highPrioritySection.getLastVisibleChild();
- ActivatableNotificationView previousFirstLowPriorityChild =
- lowPrioritySection.getFirstVisibleChild();
- ActivatableNotificationView lastHighPriorityChild = getLastHighPriorityChild();
- ActivatableNotificationView firstLowPriorityChild = getFirstLowPriorityChild();
- if (lastHighPriorityChild != null && firstLowPriorityChild != null) {
- highPrioritySection.setFirstVisibleChild(firstChild);
- highPrioritySection.setLastVisibleChild(lastHighPriorityChild);
- lowPrioritySection.setFirstVisibleChild(firstLowPriorityChild);
- lowPrioritySection.setLastVisibleChild(lastChild);
- } else if (lastHighPriorityChild != null) {
- highPrioritySection.setFirstVisibleChild(firstChild);
- highPrioritySection.setLastVisibleChild(lastChild);
- lowPrioritySection.setFirstVisibleChild(null);
- lowPrioritySection.setLastVisibleChild(null);
- } else {
- highPrioritySection.setFirstVisibleChild(null);
- highPrioritySection.setLastVisibleChild(null);
- lowPrioritySection.setFirstVisibleChild(firstChild);
- lowPrioritySection.setLastVisibleChild(lastChild);
- }
- return lastHighPriorityChild != previousLastHighPriorityChild
- || firstLowPriorityChild != previousFirstLowPriorityChild;
- } else {
- highPrioritySection.setFirstVisibleChild(firstChild);
- highPrioritySection.setLastVisibleChild(lastChild);
- return false;
- }
- }
-
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onViewAddedInternal(ExpandableView child) {
updateHideSensitiveForChild(child);
@@ -4595,11 +4540,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return mAmbientState.isDimmed();
}
- @VisibleForTesting
- int getSectionBoundaryIndex(int boundaryNum) {
- return mAmbientState.getSectionBoundaryIndex(boundaryNum);
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setDimAmount(float dimAmount) {
mDimAmount = dimAmount;
@@ -4984,7 +4924,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
} else {
child.setMinClipTopAmount(0);
}
- previousChildWillBeDismissed = canChildBeDismissed(child);
+ previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child);
}
}
@@ -5540,7 +5480,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void clearAllNotifications() {
+ private void clearNotifications(
+ @SelectedRows int selection,
+ boolean closeShade) {
// animate-swipe all dismissable notifications, then animate the shade closed
int numChildren = getChildCount();
@@ -5552,7 +5494,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
boolean parentVisible = false;
boolean hasClipBounds = child.getClipBounds(mTmpRect);
- if (canChildBeDismissed(child)) {
+ if (includeChildInDismissAll(row, selection)) {
viewsToRemove.add(row);
if (child.getVisibility() == View.VISIBLE
&& (!hasClipBounds || mTmpRect.height() > 0)) {
@@ -5566,51 +5508,94 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
List<ExpandableNotificationRow> children = row.getNotificationChildren();
if (children != null) {
for (ExpandableNotificationRow childRow : children) {
- viewsToRemove.add(childRow);
- if (parentVisible && row.areChildrenExpanded()
- && canChildBeDismissed(childRow)) {
- hasClipBounds = childRow.getClipBounds(mTmpRect);
- if (childRow.getVisibility() == View.VISIBLE
- && (!hasClipBounds || mTmpRect.height() > 0)) {
- viewsToHide.add(childRow);
+ if (includeChildInDismissAll(row, selection)) {
+ viewsToRemove.add(childRow);
+ if (parentVisible && row.areChildrenExpanded()) {
+ hasClipBounds = childRow.getClipBounds(mTmpRect);
+ if (childRow.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
+ viewsToHide.add(childRow);
+ }
}
}
}
}
}
}
+
if (viewsToRemove.isEmpty()) {
- mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ if (closeShade) {
+ mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ }
return;
}
- mShadeController.addPostCollapseAction(() -> {
- setDismissAllInProgress(false);
+ performDismissAllAnimations(viewsToHide, closeShade, () -> {
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
- if (canChildBeDismissed(rowToRemove)) {
- mEntryManager.removeNotification(rowToRemove.getEntry().key, null /* ranking */,
- NotificationListenerService.REASON_CANCEL_ALL);
+ if (StackScrollAlgorithm.canChildBeDismissed(rowToRemove)) {
+ if (selection == ROWS_ALL) {
+ // TODO: This is a listener method; we shouldn't be calling it. Can we just
+ // call performRemoveNotification as below?
+ mEntryManager.removeNotification(
+ rowToRemove.getEntry().key,
+ null /* ranking */,
+ NotificationListenerService.REASON_CANCEL_ALL);
+ } else {
+ mEntryManager.performRemoveNotification(
+ rowToRemove.getEntry().notification,
+ NotificationListenerService.REASON_CANCEL_ALL);
+ }
} else {
rowToRemove.resetTranslation();
}
}
- try {
- mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
- } catch (Exception ex) {
+ if (selection == ROWS_ALL) {
+ try {
+ mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ } catch (Exception ex) {
+ }
}
});
+ }
- performDismissAllAnimations(viewsToHide);
+ private boolean includeChildInDismissAll(
+ ExpandableNotificationRow row,
+ @SelectedRows int selection) {
+ return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection);
}
+ /**
+ * Given a list of rows, animates them away in a staggered fashion as if they were dismissed.
+ * Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete
+ * handler.
+ *
+ * @param hideAnimatedList List of rows to animated away. Should only be views that are
+ * currently visible, or else the stagger will look funky.
+ * @param closeShade Whether to close the shade after the stagger animation completes.
+ * @param onAnimationComplete Called after the entire animation completes (including the shade
+ * closing if appropriate). The rows must be dismissed for real here.
+ */
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
- Runnable animationFinishAction = () -> {
- mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ private void performDismissAllAnimations(
+ final ArrayList<View> hideAnimatedList,
+ final boolean closeShade,
+ final Runnable onAnimationComplete) {
+
+ final Runnable onSlideAwayAnimationComplete = () -> {
+ if (closeShade) {
+ mShadeController.addPostCollapseAction(() -> {
+ setDismissAllInProgress(false);
+ onAnimationComplete.run();
+ });
+ mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ } else {
+ setDismissAllInProgress(false);
+ onAnimationComplete.run();
+ }
};
if (hideAnimatedList.isEmpty()) {
- animationFinishAction.run();
+ onSlideAwayAnimationComplete.run();
return;
}
@@ -5627,7 +5612,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
View view = hideAnimatedList.get(i);
Runnable endRunnable = null;
if (i == 0) {
- endRunnable = animationFinishAction;
+ endRunnable = onSlideAwayAnimationComplete;
}
dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE);
currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
@@ -5642,7 +5627,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
R.layout.status_bar_notification_footer, this, false);
footerView.setDismissButtonClickListener(v -> {
mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
- clearAllNotifications();
+ clearNotifications(ROWS_ALL, true /* closeShade */);
});
footerView.setManageButtonClickListener(this::manageNotifications);
setFooterView(footerView);
@@ -5813,27 +5798,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
/** Updates the indices of the boundaries between sections. */
@ShadeViewRefactor(RefactorComponent.INPUT)
public void updateSectionBoundaries() {
- int gapIndex = -1;
- if (NotificationUtils.useNewInterruptionModel(mContext)) {
- int currentIndex = 0;
- final int n = getChildCount();
- for (int i = 0; i < n; i++) {
- View view = getChildAt(i);
- if (view.getVisibility() == View.GONE
- || !(view instanceof ExpandableNotificationRow)) {
- continue;
- }
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (!row.getEntry().isHighPriority()) {
- if (currentIndex > 0) {
- gapIndex = currentIndex;
- }
- break;
- }
- currentIndex++;
- }
- }
- mAmbientState.setSectionBoundaryIndex(0, gapIndex);
+ mSectionsManager.updateSectionBoundaries();
}
private void updateContinuousBackgroundDrawing() {
@@ -5869,6 +5834,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mSwipeHelper.resetExposedMenuView(animate, force);
}
+ private static boolean matchesSelection(
+ ExpandableNotificationRow row,
+ @SelectedRows int selection) {
+ switch (selection) {
+ case ROWS_ALL:
+ return true;
+ case ROWS_HIGH_PRIORITY:
+ return row.getEntry().isHighPriority();
+ case ROWS_GENTLE:
+ return !row.getEntry().isHighPriority();
+ default:
+ throw new IllegalArgumentException("Unknown selection: " + selection);
+ }
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
static class AnimationEvent {
@@ -6353,7 +6333,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public boolean canChildBeDismissed(View v) {
- return NotificationStackScrollLayout.this.canChildBeDismissed(v);
+ return StackScrollAlgorithm.canChildBeDismissed(v);
}
@Override
@@ -6560,4 +6540,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public ExpandHelper.Callback getExpandHelperCallback() {
return mExpandHelperCallback;
}
+
+ /** Enum for selecting some or all notification rows (does not included non-notif views). */
+ @Retention(SOURCE)
+ @IntDef({ROWS_ALL, ROWS_HIGH_PRIORITY, ROWS_GENTLE})
+ public @interface SelectedRows {}
+ /** All rows representing notifs. */
+ public static final int ROWS_ALL = 0;
+ /** Only rows where entry.isHighPriority() is true. */
+ public static final int ROWS_HIGH_PRIORITY = 1;
+ /** Only rows where entry.isHighPriority() is false. */
+ public static final int ROWS_GENTLE = 2;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
new file mode 100644
index 000000000000..e2f702dcb732
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.notification.stack;
+
+import android.content.Context;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+
+/**
+ * Similar in size and appearance to the NotificationShelf, appears at the beginning of some
+ * notification sections. Currently only used for gentle notifications.
+ */
+public class SectionHeaderView extends ActivatableNotificationView {
+ private View mContents;
+ private TextView mLabelView;
+ private ImageView mClearAllButton;
+
+ private final RectF mTmpRect = new RectF();
+
+ public SectionHeaderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mContents = findViewById(R.id.content);
+ mLabelView = findViewById(R.id.header_label);
+ mClearAllButton = findViewById(R.id.btn_clear_all);
+ }
+
+ @Override
+ protected View getContentView() {
+ return mContents;
+ }
+
+ /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
+ void onUiModeChanged() {
+ updateBackgroundColors();
+ mLabelView.setTextColor(
+ getContext().getColor(R.color.notification_section_header_label_color));
+ mClearAllButton.setImageResource(
+ R.drawable.status_bar_notification_section_header_clear_btn);
+ }
+
+ void setAreThereDismissableGentleNotifs(boolean areThereDismissableGentleNotifs) {
+ mClearAllButton.setVisibility(areThereDismissableGentleNotifs ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ protected boolean disallowSingleClick(MotionEvent event) {
+ // Disallow single click on lockscreen if user is tapping on clear all button
+ mTmpRect.set(
+ mClearAllButton.getLeft(),
+ mClearAllButton.getTop(),
+ mClearAllButton.getLeft() + mClearAllButton.getWidth(),
+ mClearAllButton.getTop() + mClearAllButton.getHeight());
+ return mTmpRect.contains(event.getX(), event.getY());
+ }
+
+ /**
+ * Fired whenever the user clicks on the body of the header (e.g. no sub-buttons or anything).
+ */
+ void setOnHeaderClickListener(View.OnClickListener listener) {
+ mContents.setOnClickListener(listener);
+ }
+
+ /** Fired when the user clicks on the "X" button on the far right of the header. */
+ void setOnClearAllClickListener(View.OnClickListener listener) {
+ mClearAllButton.setOnClickListener(listener);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index f97a7e653104..60061c6a9ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -58,7 +58,9 @@ public class StackScrollAlgorithm {
private float mHeadsUpInset;
private int mPinnedZTranslationExtra;
- public StackScrollAlgorithm(Context context, ViewGroup hostView) {
+ public StackScrollAlgorithm(
+ Context context,
+ ViewGroup hostView) {
mHostView = hostView;
initView(context);
}
@@ -364,22 +366,15 @@ public class StackScrollAlgorithm {
*/
private void updatePositionsForState(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
-
if (ANCHOR_SCROLLING) {
float currentYPosition = algorithmState.anchorViewY;
int childCount = algorithmState.visibleChildren.size();
for (int i = algorithmState.anchorViewIndex; i < childCount; i++) {
- if (i > algorithmState.anchorViewIndex && ambientState.beginsNewSection(i)) {
- currentYPosition += mGapHeight;
- }
currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition,
false /* reverse */);
}
currentYPosition = algorithmState.anchorViewY;
for (int i = algorithmState.anchorViewIndex - 1; i >= 0; i--) {
- if (ambientState.beginsNewSection(i + 1)) {
- currentYPosition -= mGapHeight;
- }
currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition,
true /* reverse */);
}
@@ -388,9 +383,6 @@ public class StackScrollAlgorithm {
float currentYPosition = -algorithmState.scrollY;
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
- if (ambientState.beginsNewSection(i)) {
- currentYPosition += mGapHeight;
- }
currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition,
false /* reverse */);
}
@@ -421,8 +413,15 @@ public class StackScrollAlgorithm {
float currentYPosition,
boolean reverse) {
ExpandableView child = algorithmState.visibleChildren.get(i);
+ final boolean applyGapHeight =
+ childNeedsGapHeight(ambientState.getSectionProvider(), algorithmState, i, child);
ExpandableViewState childViewState = child.getViewState();
childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
+
+ if (applyGapHeight && !reverse) {
+ currentYPosition += mGapHeight;
+ }
+
int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
if (reverse) {
@@ -459,6 +458,9 @@ public class StackScrollAlgorithm {
if (reverse) {
currentYPosition = childViewState.yTranslation;
+ if (applyGapHeight) {
+ currentYPosition -= mGapHeight;
+ }
} else {
currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
if (currentYPosition <= 0) {
@@ -473,6 +475,18 @@ public class StackScrollAlgorithm {
return currentYPosition;
}
+ private boolean childNeedsGapHeight(
+ SectionProvider sectionProvider,
+ StackScrollAlgorithmState algorithmState,
+ int visibleIndex,
+ View child) {
+ boolean needsGapHeight = sectionProvider.beginsSection(child) && visibleIndex > 0;
+ if (ANCHOR_SCROLLING) {
+ needsGapHeight &= visibleIndex != algorithmState.anchorViewIndex;
+ }
+ return needsGapHeight;
+ }
+
protected int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
ExpandableView child) {
return algorithmState.getPaddingAfterChild(child);
@@ -727,4 +741,15 @@ public class StackScrollAlgorithm {
}
}
+ /**
+ * Interface for telling the SSA when a new notification section begins (so it can add in
+ * appropriate margins).
+ */
+ public interface SectionProvider {
+ /**
+ * True if this view starts a new "section" of notifications, such as the gentle
+ * notifications section. False if sections are not enabled.
+ */
+ boolean beginsSection(View view);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9d24e1efc66a..168813a02252 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.SysUiServiceProvider.getComponent;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.animation.Animator;
@@ -2992,7 +2993,7 @@ public class NotificationPanelView extends PanelView implements
}
public boolean hasActiveClearableNotifications() {
- return mNotificationStackScroller.hasActiveClearableNotifications();
+ return mNotificationStackScroller.hasActiveClearableNotifications(ROWS_ALL);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c01367a4d213..776be00f8ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3487,7 +3487,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// TODO: Figure out way to remove these.
public NavigationBarView getNavigationBarView() {
- return mNavigationBarController.getDefaultNavigationBarView();
+ return mNavigationBarController.getNavigationBarView(mDisplayId);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
new file mode 100644
index 000000000000..67c4a92bbb02
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.notification.stack;
+
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.ActivityStarterDelegate;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationSectionsManagerTest extends SysuiTestCase {
+
+ @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ @Mock private NotificationStackScrollLayout mNssl;
+ @Mock private ActivityStarterDelegate mActivityStarterDelegate;
+
+ private NotificationSectionsManager mSectionsManager;
+
+ @Before
+ public void setUp() {
+ mSectionsManager = new NotificationSectionsManager(mNssl, mActivityStarterDelegate, true);
+ // Required in order for the header inflation to work properly
+ when(mNssl.generateLayoutParams(any(AttributeSet.class)))
+ .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ mSectionsManager.inflateViews(mContext);
+ when(mNssl.indexOfChild(any(View.class))).thenReturn(-1);
+ }
+
+ @Test
+ public void testInsertHeader() {
+ // GIVEN a stack with HI and LO rows but no section headers
+ setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+
+ // WHEN we update the section headers
+ mSectionsManager.updateSectionBoundaries();
+
+ // THEN a LO section header is added
+ verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3);
+ }
+
+ @Test
+ public void testRemoveHeader() {
+ // GIVEN a stack that originally had a header between the HI and LO sections
+ setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+
+ // WHEN the last LO row is replaced with a HI row
+ setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HEADER, ChildType.HIPRI);
+ clearInvocations(mNssl);
+ mSectionsManager.updateSectionBoundaries();
+
+ // THEN the LO section header is removed
+ verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
+ }
+
+ @Test
+ public void testDoNothingIfHeaderAlreadyRemoved() {
+ // GIVEN a stack with only HI rows
+ setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI);
+
+ // WHEN we update the sections headers
+ mSectionsManager.updateSectionBoundaries();
+
+ // THEN we don't add any section headers
+ verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt());
+ }
+
+ @Test
+ public void testMoveHeaderForward() {
+ // GIVEN a stack that originally had a header between the HI and LO sections
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.HIPRI,
+ ChildType.HIPRI,
+ ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+
+ // WHEN the LO section moves forward
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.HIPRI,
+ ChildType.LOPRI,
+ ChildType.HEADER,
+ ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+
+ // THEN the LO section header is also moved forward
+ verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
+ }
+
+ @Test
+ public void testMoveHeaderBackward() {
+ // GIVEN a stack that originally had a header between the HI and LO sections
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.LOPRI,
+ ChildType.LOPRI,
+ ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+
+ // WHEN the LO section moves backward
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.HEADER,
+ ChildType.HIPRI,
+ ChildType.HIPRI,
+ ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+
+ // THEN the LO section header is also moved backward (with appropriate index shifting)
+ verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 3);
+ }
+
+ @Test
+ public void testHeaderRemovedFromTransientParent() {
+ // GIVEN a stack where the header is animating away
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.LOPRI,
+ ChildType.LOPRI,
+ ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.HEADER);
+ mSectionsManager.updateSectionBoundaries();
+ clearInvocations(mNssl);
+
+ ViewGroup transientParent = mock(ViewGroup.class);
+ mSectionsManager.getGentleHeaderView().setTransientContainer(transientParent);
+
+ // WHEN the LO section reappears
+ setStackState(
+ ChildType.HIPRI,
+ ChildType.LOPRI);
+ mSectionsManager.updateSectionBoundaries();
+
+ // THEN the header is first removed from the transient parent before being added to the
+ // NSSL.
+ verify(transientParent).removeTransientView(mSectionsManager.getGentleHeaderView());
+ verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 1);
+ }
+
+ private enum ChildType { HEADER, HIPRI, LOPRI }
+
+ private void setStackState(ChildType... children) {
+ when(mNssl.getChildCount()).thenReturn(children.length);
+ for (int i = 0; i < children.length; i++) {
+ View child;
+ switch (children[i]) {
+ case HEADER:
+ child = mSectionsManager.getGentleHeaderView();
+ break;
+ case HIPRI:
+ case LOPRI:
+ ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
+ RETURNS_DEEP_STUBS);
+ when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
+ when(notifRow.getEntry().isHighPriority())
+ .thenReturn(children[i] == ChildType.HIPRI);
+ when(notifRow.getParent()).thenReturn(mNssl);
+ child = notifRow;
+ break;
+ default:
+ throw new RuntimeException("Unknown ChildType: " + children[i]);
+ }
+ when(mNssl.getChildAt(i)).thenReturn(child);
+ when(mNssl.indexOfChild(child)).thenReturn(i);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 04f911a2b0e8..09b8062390bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -46,6 +46,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.Dependency;
import com.android.systemui.ExpandHelper;
import com.android.systemui.InitController;
@@ -118,6 +119,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Before
@UiThreadTest
public void setUp() throws Exception {
+ mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
+
// Inject dependencies before initializing the layout
mDependency.injectTestDependency(
NotificationBlockingHelperManager.class,
@@ -146,7 +152,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
true /* allowLongPress */, mNotificationRoundnessManager,
new AmbientPulseManager(mContext),
- mock(DynamicPrivacyController.class));
+ mock(DynamicPrivacyController.class),
+ mock(ActivityStarterDelegate.class));
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelf(notificationShelf);
mStackScroller.setStatusBar(mBar);
@@ -166,11 +173,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
doNothing().when(mExpandHelper).cancelImmediately();
doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
doNothing().when(notificationShelf).fadeInTranslating();
-
- mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
- NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
- Settings.Secure.putInt(mContext.getContentResolver(),
- NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
}
@After
@@ -350,62 +352,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
- public void testUpdateGapIndex_allHighPriority() {
- when(mStackScroller.getChildCount()).thenReturn(3);
- for (int i = 0; i < 3; i++) {
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class,
- RETURNS_DEEP_STUBS);
- String key = Integer.toString(i);
- when(row.getStatusBarNotification().getKey()).thenReturn(key);
- when(row.getEntry().isHighPriority()).thenReturn(true);
- when(mStackScroller.getChildAt(i)).thenReturn(row);
- }
-
- mStackScroller.updateSectionBoundaries();
- assertEquals(-1, mStackScroller.getSectionBoundaryIndex(0));
- }
-
- @Test
- public void testUpdateGapIndex_allLowPriority() {
- when(mStackScroller.getChildCount()).thenReturn(3);
- for (int i = 0; i < 3; i++) {
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class,
- RETURNS_DEEP_STUBS);
- String key = Integer.toString(i);
- when(row.getStatusBarNotification().getKey()).thenReturn(key);
- when(row.getEntry().isHighPriority()).thenReturn(false);
- when(mStackScroller.getChildAt(i)).thenReturn(row);
- }
-
- mStackScroller.updateSectionBoundaries();
- assertEquals(-1, mStackScroller.getSectionBoundaryIndex(0));
- }
-
- @Test
- public void testUpdateGapIndex_gapExists() {
- when(mStackScroller.getChildCount()).thenReturn(6);
- for (int i = 0; i < 6; i++) {
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class,
- RETURNS_DEEP_STUBS);
- String key = Integer.toString(i);
- when(row.getStatusBarNotification().getKey()).thenReturn(key);
- when(row.getEntry().isHighPriority()).thenReturn(i < 3);
- when(mStackScroller.getChildAt(i)).thenReturn(row);
- }
-
- mStackScroller.updateSectionBoundaries();
- assertEquals(3, mStackScroller.getSectionBoundaryIndex(0));
- }
-
- @Test
- public void testUpdateGapIndex_empty() {
- when(mStackScroller.getChildCount()).thenReturn(0);
-
- mStackScroller.updateSectionBoundaries();
- assertEquals(-1, mStackScroller.getSectionBoundaryIndex(0));
- }
-
- @Test
public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
clearInvocations(mStackScroller);
mStackScroller.onDensityOrFontScaleChanged();
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 65338cb2126f..e30e166a46b5 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -263,6 +263,14 @@ message MetricsEvent {
PREVIOUSLY_VISIBLE = 2;
}
+ // Types for ACTION_SHORTCUTS_CHANGED
+ enum ShortcutsChangesInfo {
+ SHORTCUTS_CHANGED_UNKNOWN = 0;
+ SHORTCUTS_CHANGED_USER_ID = 1;
+ SHORTCUTS_CHANGED_PACKAGE_COUNT = 2;
+ SHORTCUTS_CHANGED_SHORTCUT_COUNT = 3;
+ }
+
// Explanations for notification importance, derived from
// NotificationRecord.mImportanceExplanation.
enum NotificationImportanceExplanation {
@@ -4183,6 +4191,8 @@ message MetricsEvent {
// Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
// Tag FIELD_AUTOFILL_NUMBER_REQUESTS: number of requests made to the service (each request
// is logged by a separate AUTOFILL_REQUEST metric)
+ // NOTE: starting on OS Q, it also added the following fields:
+ // TAg FIELD_AUTOFILL_AUGMENTED_ONLY: if the session was used just for augmented autofill
AUTOFILL_SESSION_FINISHED = 919;
// meta-event: a reader has checkpointed the log here.
@@ -7222,6 +7232,64 @@ message MetricsEvent {
// OS: Q
ASSISTANT = 1716;
+ // ACTION: Published shortcuts in ShortcutManager changed
+ // TYPE: All the SHORTCUTS_CHANGED_* values in ShortcutsChangesInfo
+ // OS: Q
+ ACTION_SHORTCUTS_CHANGED = 1717;
+
+ // ACTION: Direct share targets loaded via ShortcutManager
+ // OS: Q
+ ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER = 1718;
+
+ // ACTION: Direct share targets loaded via ChooserService
+ // OS: Q
+ ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE = 1719;
+
+ // Field indicating that an autofill session was created just for augmented autofill purposes.
+ // OS: Q
+ // Value: 1 for true, absent when false
+ FIELD_AUTOFILL_AUGMENTED_ONLY = 1720;
+
+ // The augmented autofill service set its whitelisted packages and activities.
+ // OS: Q
+ // Tag FIELD_AUTOFILL_SERVICE: Package of the augmented autofill service that processed the
+ // request
+ // Tag FIELD_AUTOFILL_NUMBER_PACKAGES: Number of whitelisted packages.
+ // Tag FIELD_AUTOFILL_NUMBER_ACTIVITIES: Number of whitelisted activities.
+ AUTOFILL_AUGMENTED_WHITELIST_REQUEST = 1721;
+
+ // Generic field used to indicate the number of packages in an Autofill metric (typically a
+ // whitelist request).
+ // OS: Q
+ FIELD_AUTOFILL_NUMBER_PACKAGES = 1722;
+
+ // Generic field used to indicate the number of activities in an Autofill metric (typically a
+ // whitelist request).
+ // OS: Q
+ FIELD_AUTOFILL_NUMBER_ACTIVITIES = 1723;
+
+ // Reports the result of a request made to the augmented autofill service
+ // OS: Q
+ // Type TYPE_UNKNOWN: if the type of response could not be determined
+ // Type TYPE_SUCCESS: service called onSucess() passing null
+ // Type TYPE_OPEN: service shown the UI
+ // Type TYPE_CLOSE: service hid the UI
+ // Type TYPE_ERROR: service timed out responding
+
+ // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+ // Tag FIELD_AUTOFILL_SERVICE: Package of the augmented autofill service that processed the
+ // request
+ // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric
+ // Tag FIELD_AUTOFILL_DURATION: how long it took (in ms) to the service to respond, or -1 if the
+ // type of response could not be determined
+ AUTOFILL_AUGMENTED_RESPONSE = 1724;
+
+ // ---- Skipping ahead to avoid conflicts between master and release branches.
+ // OPEN: Settings > System > Gestures > Global Actions Panel
+ // CATEGORY: SETTINGS
+ // OS: Q
+ GLOBAL_ACTIONS_PANEL_SETTINGS = 1800;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 386dec472019..6bb1cfaf11c2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1177,8 +1177,8 @@ final class AutofillManagerServiceImpl
* @return whether caller UID is the augmented autofill service for the user
*/
@GuardedBy("mLock")
- boolean setAugmentedAutofillWhitelistLocked(List<String> packages,
- List<ComponentName> activities, int callingUid) {
+ boolean setAugmentedAutofillWhitelistLocked(@Nullable List<String> packages,
+ @Nullable List<ComponentName> activities, int callingUid) {
if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked",
callingUid)) {
@@ -1189,8 +1189,25 @@ final class AutofillManagerServiceImpl
+ activities + ")");
}
whitelistForAugmentedAutofillPackages(packages, activities);
+ final String serviceName;
+ if (mRemoteAugmentedAutofillServiceInfo != null) {
+ serviceName = mRemoteAugmentedAutofillServiceInfo.getComponentName()
+ .flattenToShortString();
+ } else {
+ Slog.e(TAG, "setAugmentedAutofillWhitelistLocked(): no service");
+ serviceName = "N/A";
+ }
+
+ final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_AUGMENTED_WHITELIST_REQUEST)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, serviceName);
+ if (packages != null) {
+ log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_PACKAGES, packages.size());
+ }
+ if (activities != null) {
+ log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_ACTIVITIES, activities.size());
+ }
+ mMetricsLogger.write(log);
- // TODO(b/122858578): log metrics
return true;
}
@@ -1233,7 +1250,6 @@ final class AutofillManagerServiceImpl
}
/**
- *
* @throws IllegalArgumentException if packages or components are empty.
*/
private void whitelistForAugmentedAutofillPackages(@Nullable List<String> packages,
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 609904b32230..d2b71e591b22 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -16,6 +16,8 @@
package com.android.server.autofill;
+import static android.service.autofill.augmented.Helper.logResponse;
+
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
@@ -43,6 +45,7 @@ import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.infra.AbstractSinglePendingRequestRemoteService;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
final class RemoteAugmentedAutofillService
@@ -173,6 +176,7 @@ final class RemoteAugmentedAutofillService
private final @Nullable AutofillValue mFocusedValue;
private final @NonNull IAutoFillManagerClient mClient;
private final @NonNull ComponentName mActivityComponent;
+ private final int mSessionId;
private final int mTaskId;
private final long mRequestTime = SystemClock.elapsedRealtime();
private final @NonNull IFillCallback mCallback;
@@ -184,6 +188,7 @@ final class RemoteAugmentedAutofillService
@Nullable AutofillValue focusedValue) {
super(service, sessionId);
mClient = client;
+ mSessionId = sessionId;
mTaskId = taskId;
mActivityComponent = activityComponent;
mFocusedId = focusedId;
@@ -283,6 +288,8 @@ final class RemoteAugmentedAutofillService
remoteService.dispatchOnFillTimeout(cancellation);
}
finish();
+ logResponse(MetricsEvent.TYPE_ERROR, remoteService.getComponentName().getPackageName(),
+ mActivityComponent, mSessionId, remoteService.mRequestTimeoutMs);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 1a0353cde8ce..e61fa326215f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -570,7 +570,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private void requestNewFillResponseLocked(@NonNull ViewState viewState, int newState,
int flags) {
if (mForAugmentedAutofillOnly) {
- // TODO(b/122858578): log metrics
if (sVerbose) {
Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead "
+ "(mForAugmentedAutofillOnly=" + mForAugmentedAutofillOnly
@@ -3253,6 +3252,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS,
totalAugmentedRequests);
}
+ if (mForAugmentedAutofillOnly) {
+ log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_AUGMENTED_ONLY, 1);
+ }
mMetricsLogger.write(log);
return mRemoteFillService;
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 1220e82485e7..b66de22201b8 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1764,8 +1764,7 @@ class AlarmManagerService extends SystemService {
+ ", callingPackage: " + callingPackage;
// STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
Slog.wtf(TAG, errorMsg);
- // TODO b/129995049: Resume throwing after some soak time without errors
- // throw new UnsupportedOperationException(errorMsg);
+ throw new UnsupportedOperationException(errorMsg);
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, directReceiver, listenerTag, flags, true, workSource,
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 7b5b419a7aa0..103a0c7bafdb 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -529,8 +529,7 @@ public class PackageWatchdog {
while (pit.hasNext()) {
MonitoredPackage monitoredPackage = pit.next();
String packageName = monitoredPackage.getName();
- if (monitoredPackage.getHealthCheckStateLocked()
- != MonitoredPackage.STATE_PASSED) {
+ if (monitoredPackage.isPendingHealthChecksLocked()) {
packages.add(packageName);
}
}
@@ -1093,7 +1092,10 @@ public class PackageWatchdog {
*/
@GuardedBy("mLock")
public long getShortestScheduleDurationMsLocked() {
- return Math.min(toPositive(mDurationMs), toPositive(mHealthCheckDurationMs));
+ // Consider health check duration only if #isPendingHealthChecksLocked is true
+ return Math.min(toPositive(mDurationMs),
+ isPendingHealthChecksLocked()
+ ? toPositive(mHealthCheckDurationMs) : Long.MAX_VALUE);
}
/**
@@ -1106,6 +1108,15 @@ public class PackageWatchdog {
}
/**
+ * Returns {@code true} if the package, {@link #getName} is expecting health check results
+ * {@code false} otherwise.
+ */
+ @GuardedBy("mLock")
+ public boolean isPendingHealthChecksLocked() {
+ return mHealthCheckState == STATE_ACTIVE || mHealthCheckState == STATE_INACTIVE;
+ }
+
+ /**
* Updates the health check state based on {@link #mHasPassedHealthCheck}
* and {@link #mHealthCheckDurationMs}.
*
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 28bc34859e6c..225c08092b49 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -342,7 +342,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
Integer newDefaultSubIdObj = new Integer(intent.getIntExtra(
PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.getDefaultSubscriptionId()));
- int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
+ int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
SubscriptionManager.getPhoneId(mDefaultSubId));
if (DBG) {
log("onReceive:current mDefaultSubId=" + mDefaultSubId
@@ -1935,8 +1935,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mCallQuality=" + mCallQuality);
pw.println("mCallAttributes=" + mCallAttributes);
- pw.println("mDefaultPhoneId" + mDefaultPhoneId);
- pw.println("mDefaultSubId" + mDefaultSubId);
+ pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
+ pw.println("mDefaultSubId=" + mDefaultSubId);
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 46c8ce77d7cf..4d0d3d2dc578 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -272,7 +272,6 @@ import android.os.UserManager;
import android.os.WorkSource;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
-import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.sysprop.VoldProperties;
@@ -5737,17 +5736,6 @@ public class ActivityManagerService extends IActivityManager.Stub
owningUid, exported);
}
- @Override
- public int checkPermissionWithDenialHintForwarding(String permission, int pid, int uid,
- List<String> permissionDenialHints) {
- List<String> prev = PermissionManager.resetPermissionDenialHints(permissionDenialHints);
- try {
- return checkPermission(permission, pid, uid);
- } finally {
- PermissionManager.resetPermissionDenialHints(prev);
- }
- }
-
/**
* As the only public entry point for permissions checking, this method
* can enforce the semantic that requesting a check on a null global
@@ -5760,7 +5748,6 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
- PermissionManager.addPermissionDenialHint("Permission is null");
return PackageManager.PERMISSION_DENIED;
}
return checkComponentPermission(permission, pid, uid, -1, true);
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index f599adb5118a..85fb1e0f4bdf 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -473,6 +473,20 @@ public final class ColorDisplayService extends SystemService {
onDisplayColorModeChanged(getColorModeInternal());
}
+ private boolean isAccessiblityDaltonizerEnabled() {
+ return Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
+ }
+
+ private boolean isAccessiblityInversionEnabled() {
+ return Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
+ }
+
+ private boolean isAccessibilityEnabled() {
+ return isAccessiblityDaltonizerEnabled() || isAccessiblityInversionEnabled();
+ }
+
/**
* Apply the accessibility daltonizer transform based on the settings value.
*/
@@ -480,11 +494,10 @@ public final class ColorDisplayService extends SystemService {
if (mCurrentUser == UserHandle.USER_NULL) {
return;
}
- final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
- Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
- final int daltonizerMode = enabled ? Secure.getIntForUser(getContext().getContentResolver(),
- Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
- AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
+ final int daltonizerMode = isAccessiblityDaltonizerEnabled()
+ ? Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+ AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
: AccessibilityManager.DALTONIZER_DISABLED;
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
@@ -506,11 +519,9 @@ public final class ColorDisplayService extends SystemService {
if (mCurrentUser == UserHandle.USER_NULL) {
return;
}
- final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
- Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
- enabled ? MATRIX_INVERT_COLOR : null);
+ isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null);
}
/**
@@ -598,6 +609,7 @@ public final class ColorDisplayService extends SystemService {
boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled()
&& !mNightDisplayTintController.isActivated()
+ && !isAccessibilityEnabled()
&& DisplayTransformManager.needsLinearColorMatrix());
boolean activated = mDisplayWhiteBalanceTintController.isActivated();
@@ -761,10 +773,7 @@ public final class ColorDisplayService extends SystemService {
private @ColorMode int getColorModeInternal() {
final ContentResolver cr = getContext().getContentResolver();
- if (Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
- 0, mCurrentUser) == 1
- || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
- 0, mCurrentUser) == 1) {
+ if (isAccessibilityEnabled()) {
// There are restrictions on the available color modes combined with a11y transforms.
if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
return COLOR_MODE_SATURATED;
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index 97c9c7939129..d2c6cd9f1007 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -32,6 +32,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.lang.System;
final class DisplayWhiteBalanceTintController extends TintController {
@@ -39,6 +40,7 @@ final class DisplayWhiteBalanceTintController extends TintController {
private static final int NUM_VALUES_PER_PRIMARY = 3;
// Four colors: red, green, blue, and white
private static final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
+ private static final int COLORSPACE_MATRIX_LENGTH = 9;
private final Object mLock = new Object();
@VisibleForTesting
@@ -46,14 +48,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
@VisibleForTesting
int mTemperatureMax;
private int mTemperatureDefault;
- private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ @VisibleForTesting
+ float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
@VisibleForTesting
ColorSpace.Rgb mDisplayColorSpaceRGB;
private float[] mChromaticAdaptationMatrix;
@VisibleForTesting
int mCurrentColorTemperature;
private float[] mCurrentColorTemperatureXYZ;
- private boolean mSetUp = false;
+ @VisibleForTesting
+ boolean mSetUp = false;
private float[] mMatrixDisplayWhiteBalance = new float[16];
private Boolean mIsAvailable;
@@ -73,6 +77,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
}
}
+ // Make sure display color space is valid
+ if (!isColorMatrixValid(displayColorSpaceRGB.getTransform())) {
+ Slog.e(ColorDisplayService.TAG, "Invalid display color space RGB-to-XYZ transform");
+ return;
+ }
+ if (!isColorMatrixValid(displayColorSpaceRGB.getInverseTransform())) {
+ Slog.e(ColorDisplayService.TAG, "Invalid display color space XYZ-to-RGB transform");
+ return;
+ }
+
final String[] nominalWhiteValues = res.getStringArray(
R.array.config_displayWhiteBalanceDisplayNominalWhite);
float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
@@ -157,11 +171,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
final float adaptedMaxG = result[1] + result[4] + result[7];
final float adaptedMaxB = result[2] + result[5] + result[8];
final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
for (int i = 0; i < result.length; i++) {
result[i] /= denum;
+ if (!isColorMatrixCoeffValid(result[i])) {
+ Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
+ return;
+ }
}
- Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
@@ -277,4 +296,27 @@ final class DisplayWhiteBalanceTintController extends TintController {
return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
}
+
+ private boolean isColorMatrixCoeffValid(float coeff) {
+ if (Float.isNaN(coeff) || Float.isInfinite(coeff)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean isColorMatrixValid(float[] matrix) {
+ if (matrix == null || matrix.length != COLORSPACE_MATRIX_LENGTH) {
+ return false;
+ }
+
+ for (int i = 0; i < matrix.length; i++) {
+ if (!isColorMatrixCoeffValid(matrix[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 44228eec8e94..5f1f20294bc1 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1597,8 +1597,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private void reportGnssServiceDied() {
if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
mHandler.post(() -> {
- class_init_native();
- setupNativeGnssService();
+ setupNativeGnssService(/* reinitializeGnssServiceHandle = */ true);
if (isEnabled()) {
synchronized (mLock) {
mEnabled = false;
@@ -2052,7 +2051,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
* this handler.
*/
private void handleInitialize() {
- setupNativeGnssService();
+ // class_init_native() already initializes the GNSS service handle during class loading.
+ setupNativeGnssService(/* reinitializeGnssServiceHandle = */ false);
if (native_is_gnss_visibility_control_supported()) {
mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper);
@@ -2214,8 +2214,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
pw.append(s);
}
- private void setupNativeGnssService() {
- native_init_once();
+ private void setupNativeGnssService(boolean reinitializeGnssServiceHandle) {
+ native_init_once(reinitializeGnssServiceHandle);
/*
* A cycle of native_init() and native_cleanup() is needed so that callbacks are
@@ -2244,7 +2244,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static native boolean native_is_gnss_visibility_control_supported();
- private static native void native_init_once();
+ private static native void native_init_once(boolean reinitializeGnssServiceHandle);
private native boolean native_init();
diff --git a/services/core/java/com/android/server/om/DumpState.java b/services/core/java/com/android/server/om/DumpState.java
new file mode 100644
index 000000000000..1e2e054bbc6c
--- /dev/null
+++ b/services/core/java/com/android/server/om/DumpState.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+
+/**
+ * State for dumps performed by the OverlayManagerService.
+ */
+public final class DumpState {
+ @UserIdInt private int mUserId = UserHandle.USER_ALL;
+ @Nullable private String mPackageName;
+ @Nullable private String mField;
+ private boolean mVerbose;
+
+ /** Sets the user to dump the state for */
+ public void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+ @UserIdInt public int getUserId() {
+ return mUserId;
+ }
+
+ /** Sets the name of the package to dump the state for */
+ public void setPackageName(String packageName) {
+ mPackageName = packageName;
+ }
+ @Nullable public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Sets the name of the field to dump the state of */
+ public void setField(String field) {
+ mField = field;
+ }
+ @Nullable public String getField() {
+ return mField;
+ }
+
+ /** Enables verbose dump state */
+ public void setVerbose(boolean verbose) {
+ mVerbose = verbose;
+ }
+ public boolean isVerbose() {
+ return mVerbose;
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 209ccdae75d0..da69986cd59f 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -749,15 +749,77 @@ public final class OverlayManagerService extends SystemService {
}
@Override
- protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
- @NonNull final String[] argv) {
- enforceDumpPermission("dump");
-
- final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final DumpState dumpState = new DumpState();
+ dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid()));
+
+ int opti = 0;
+ while (opti < args.length) {
+ final String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+
+ if ("-h".equals(opt)) {
+ pw.println("dump [-h] [--verbose] [--user USER_ID] [[FIELD] PACKAGE]");
+ pw.println(" Print debugging information about the overlay manager.");
+ pw.println(" With optional parameter PACKAGE, limit output to the specified");
+ pw.println(" package. With optional parameter FIELD, limit output to");
+ pw.println(" the value of that SettingsItem field. Field names are");
+ pw.println(" case insensitive and out.println the m prefix can be omitted,");
+ pw.println(" so the following are equivalent: mState, mstate, State, state.");
+ return;
+ } else if ("--user".equals(opt)) {
+ opti++;
+ if (opti >= args.length) {
+ pw.println("Error: user missing argument");
+ return;
+ }
+ try {
+ dumpState.setUserId(Integer.parseInt(args[opti]));
+ } catch (NumberFormatException e) {
+ pw.println("Error: user argument is not a number: " + args[opti]);
+ return;
+ }
+ } else if ("--verbose".equals(opt)) {
+ dumpState.setVerbose(true);
+ } else {
+ pw.println("Unknown argument: " + opt + "; use -h for help");
+ }
+ }
+ if (opti < args.length) {
+ final String arg = args[opti];
+ opti++;
+ switch (arg) {
+ case "packagename":
+ case "userid":
+ case "targetpackagename":
+ case "targetoverlayablename":
+ case "basecodepath":
+ case "state":
+ case "isenabled":
+ case "isstatic":
+ case "priority":
+ case "category":
+ dumpState.setField(arg);
+ break;
+ default:
+ dumpState.setPackageName(arg);
+ break;
+ }
+ }
+ if (dumpState.getPackageName() == null && opti < args.length) {
+ dumpState.setPackageName(args[opti]);
+ opti++;
+ }
+ enforceDumpPermission("dump");
synchronized (mLock) {
- mImpl.onDump(pw);
- mPackageManager.dump(pw, verbose);
+ mImpl.dump(pw, dumpState);
+ if (dumpState.getPackageName() == null) {
+ mPackageManager.dump(pw, dumpState);
+ }
}
}
@@ -1046,10 +1108,10 @@ public final class OverlayManagerService extends SystemService {
private static final String TAB1 = " ";
private static final String TAB2 = TAB1 + TAB1;
- public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
+ public void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
pw.println("PackageInfo cache");
- if (!verbose) {
+ if (!dumpState.isVerbose()) {
int count = 0;
final int n = mCache.size();
for (int i = 0; i < n; i++) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 092dbc817e32..6f28675d051b 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -636,9 +636,11 @@ final class OverlayManagerServiceImpl {
return true;
}
- void onDump(@NonNull final PrintWriter pw) {
- mSettings.dump(pw);
- pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
+ void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
+ mSettings.dump(pw, dumpState);
+ if (dumpState.getPackageName() == null) {
+ pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
+ }
}
@NonNull String[] getDefaultOverlayPackages() {
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index f35c70780db9..b7346d455319 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -22,6 +22,7 @@ import static com.android.server.om.OverlayManagerService.TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayInfo;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
@@ -288,35 +289,78 @@ final class OverlayManagerSettings {
return true;
}
- void dump(@NonNull final PrintWriter p) {
+ void dump(@NonNull final PrintWriter p, @NonNull DumpState dumpState) {
+ // select items to display
+ Stream<SettingsItem> items = mItems.stream();
+ if (dumpState.getUserId() != UserHandle.USER_ALL) {
+ items = items.filter(item -> item.mUserId == dumpState.getUserId());
+ }
+ if (dumpState.getPackageName() != null) {
+ items = items.filter(item -> item.mPackageName.equals(dumpState.getPackageName()));
+ }
+
+ // display items
final IndentingPrintWriter pw = new IndentingPrintWriter(p, " ");
- pw.println("Settings");
+ if (dumpState.getField() != null) {
+ items.forEach(item -> dumpSettingsItemField(pw, item, dumpState.getField()));
+ } else {
+ items.forEach(item -> dumpSettingsItem(pw, item));
+ }
+ }
+
+ private void dumpSettingsItem(@NonNull final IndentingPrintWriter pw,
+ @NonNull final SettingsItem item) {
+ pw.println(item.mPackageName + ":" + item.getUserId() + " {");
pw.increaseIndent();
- if (mItems.isEmpty()) {
- pw.println("<none>");
- return;
- }
+ pw.println("mPackageName...........: " + item.mPackageName);
+ pw.println("mUserId................: " + item.getUserId());
+ pw.println("mTargetPackageName.....: " + item.getTargetPackageName());
+ pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName());
+ pw.println("mBaseCodePath..........: " + item.getBaseCodePath());
+ pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
+ pw.println("mIsEnabled.............: " + item.isEnabled());
+ pw.println("mIsStatic..............: " + item.isStatic());
+ pw.println("mPriority..............: " + item.mPriority);
+ pw.println("mCategory..............: " + item.mCategory);
+
+ pw.decreaseIndent();
+ pw.println("}");
+ }
- final int n = mItems.size();
- for (int i = 0; i < n; i++) {
- final SettingsItem item = mItems.get(i);
- pw.println(item.mPackageName + ":" + item.getUserId() + " {");
- pw.increaseIndent();
-
- pw.println("mPackageName...........: " + item.mPackageName);
- pw.println("mUserId................: " + item.getUserId());
- pw.println("mTargetPackageName.....: " + item.getTargetPackageName());
- pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName());
- pw.println("mBaseCodePath..........: " + item.getBaseCodePath());
- pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
- pw.println("mIsEnabled.............: " + item.isEnabled());
- pw.println("mIsStatic..............: " + item.isStatic());
- pw.println("mPriority..............: " + item.mPriority);
- pw.println("mCategory..............: " + item.mCategory);
-
- pw.decreaseIndent();
- pw.println("}");
+ private void dumpSettingsItemField(@NonNull final IndentingPrintWriter pw,
+ @NonNull final SettingsItem item, @NonNull final String field) {
+ switch (field) {
+ case "packagename":
+ pw.println(item.mPackageName);
+ break;
+ case "userid":
+ pw.println(item.mUserId);
+ break;
+ case "targetpackagename":
+ pw.println(item.mTargetPackageName);
+ break;
+ case "targetoverlayablename":
+ pw.println(item.mTargetOverlayableName);
+ break;
+ case "basecodepath":
+ pw.println(item.mBaseCodePath);
+ break;
+ case "state":
+ pw.println(OverlayInfo.stateToString(item.mState));
+ break;
+ case "isenabled":
+ pw.println(item.mIsEnabled);
+ break;
+ case "isstatic":
+ pw.println(item.mIsStatic);
+ break;
+ case "priority":
+ pw.println(item.mPriority);
+ break;
+ case "category":
+ pw.println(item.mCategory);
+ break;
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index e2b1cba3819f..7ee167adfd38 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -77,13 +77,17 @@ final class OverlayManagerShellCommand extends ShellCommand {
out.println("Overlay manager (overlay) commands:");
out.println(" help");
out.println(" Print this help text.");
- out.println(" dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
+ out.println(" dump [--verbose] [--user USER_ID] [[FIELD] PACKAGE]");
out.println(" Print debugging information about the overlay manager.");
- out.println(" list [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
+ out.println(" With optional parameter PACKAGE, limit output to the specified");
+ out.println(" package. With optional parameter FIELD, limit output to");
+ out.println(" the value of that SettingsItem field. Field names are");
+ out.println(" case insensitive and out.println the m prefix can be omitted,");
+ out.println(" so the following are equivalent: mState, mstate, State, state.");
+ out.println(" list [--user USER_ID] [PACKAGE]");
out.println(" Print information about target and overlay packages.");
out.println(" Overlay packages are printed in priority order. With optional");
- out.println(" parameters PACKAGEs, limit output to the specified packages");
- out.println(" but include more information about each package.");
+ out.println(" parameter PACKAGE, limit output to the specified package.");
out.println(" enable [--user USER_ID] PACKAGE");
out.println(" Enable overlay package PACKAGE.");
out.println(" disable [--user USER_ID] PACKAGE");
@@ -116,14 +120,20 @@ final class OverlayManagerShellCommand extends ShellCommand {
return 1;
}
}
+ final String packageName = getNextArg();
final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId);
for (final String targetPackageName : allOverlays.keySet()) {
- out.println(targetPackageName);
+ if (targetPackageName.equals(packageName)) {
+ out.println(targetPackageName);
+ }
List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName);
final int n = overlaysForTarget.size();
for (int i = 0; i < n; i++) {
final OverlayInfo oi = overlaysForTarget.get(i);
+ if (!targetPackageName.equals(packageName) && !oi.packageName.equals(packageName)) {
+ continue;
+ }
String status;
switch (oi.state) {
case OverlayInfo.STATE_ENABLED_STATIC:
@@ -139,7 +149,9 @@ final class OverlayManagerShellCommand extends ShellCommand {
}
out.println(String.format("%s %s", status, oi.packageName));
}
- out.println();
+ if (targetPackageName.equals(packageName)) {
+ out.println();
+ }
}
return 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index e6313d9dcbe4..35f21496f2cc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -531,16 +531,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
- // Only system components can circumvent restricted whitelisting when installing.
- if ((params.installFlags
- & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
- && mContext.checkCallingOrSelfPermission(Manifest.permission
- .WHITELIST_RESTRICTED_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
- throw new SecurityException("You need the "
- + "android.permission.WHITELIST_RESTRICTED_PERMISSIONS permission to"
- + " use the PackageManager.INSTALL_WHITELIST_RESTRICTED_PERMISSIONS flag");
- }
-
// Defensively resize giant app icons
if (params.appIcon != null) {
final ActivityManager am = (ActivityManager) mContext.getSystemService(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 648522a61dbc..ed83cbced49f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -240,7 +240,6 @@ import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
-import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
@@ -4331,19 +4330,13 @@ public class PackageManagerService extends IPackageManager.Stub
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
- int newCallingUid = mIsolatedOwners.get(callingUid);
- PermissionManager.addPermissionDenialHint(
- "callingUid=" + callingUid + " is changed to " + newCallingUid
- + " as process is isolated");
- callingUid = newCallingUid;
+ callingUid = mIsolatedOwners.get(callingUid);
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final boolean callerIsInstantApp = instantAppPkgName != null;
if (ps == null) {
if (callerIsInstantApp) {
// pretend the application exists, but, needs to be filtered
- PermissionManager.addPermissionDenialHint(
- "No package setting but caller is instant app");
return true;
}
return false;
@@ -4355,7 +4348,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (callerIsInstantApp) {
// both caller and target are both instant, but, different applications, filter
if (ps.getInstantApp(userId)) {
- PermissionManager.addPermissionDenialHint("Apps are different instant apps");
return true;
}
// request for a specific component; if it hasn't been explicitly exposed through
@@ -4367,23 +4359,10 @@ public class PackageManagerService extends IPackageManager.Stub
&& isCallerSameApp(instrumentation.info.targetPackage, callingUid)) {
return false;
}
- if (!isComponentVisibleToInstantApp(component, componentType)) {
- PermissionManager.addPermissionDenialHint(
- "Component is not visible to instant app: "
- + component.flattenToShortString());
- return true;
- } else {
- return false;
- }
+ return !isComponentVisibleToInstantApp(component, componentType);
}
// request for application; if no components have been explicitly exposed, filter
- if (!ps.pkg.visibleToInstantApps) {
- PermissionManager.addPermissionDenialHint(
- "Package is not visible to instant app: " + ps.pkg.packageName);
- return true;
- } else {
- return false;
- }
+ return !ps.pkg.visibleToInstantApps;
}
if (ps.getInstantApp(userId)) {
// caller can see all components of all instant applications, don't filter
@@ -4392,19 +4371,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
// request for a specific instant application component, filter
if (component != null) {
- PermissionManager.addPermissionDenialHint(
- "Component is not null: " + component.flattenToShortString());
return true;
}
// request for an instant application; if the caller hasn't been granted access, filter
- if (!mInstantAppRegistry.isInstantAccessGranted(
- userId, UserHandle.getAppId(callingUid), ps.appId)) {
- PermissionManager.addPermissionDenialHint(
- "Instant access is not granted: " + ps.appId);
- return true;
- } else {
- return false;
- }
+ return !mInstantAppRegistry.isInstantAccessGranted(
+ userId, UserHandle.getAppId(callingUid), ps.appId);
}
return false;
}
@@ -5649,17 +5620,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public int checkUidPermissionWithDenialHintForwarding(String permName, int uid,
- List<String> permissionDenialHints) {
- List<String> prev = PermissionManager.resetPermissionDenialHints(permissionDenialHints);
- try {
- return checkUidPermission(permName, uid);
- } finally {
- PermissionManager.resetPermissionDenialHints(prev);
- }
- }
-
- @Override
public int checkUidPermission(String permName, int uid) {
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mPackages) {
@@ -11766,7 +11726,12 @@ public class PackageManagerService extends IPackageManager.Stub
"Code and resource paths haven't been set correctly");
}
- if (mApexManager.isApexPackage(pkg.packageName)) {
+ // Check that there is an APEX package with the same name only during install/first boot
+ // after OTA.
+ final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
+ final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
+ if ((isUserInstall || isFirstBootOrUpgrade)
+ && mApexManager.isApexPackage(pkg.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
pkg.packageName + " is an APEX package and can't be installed as an APK.");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 33dd48a1ac6a..fbf074e3ba15 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2351,9 +2351,10 @@ class PackageManagerShellCommand extends ShellCommand {
break;
case "-g":
sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
- case "-w":
- sessionParams.installFlags |=
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
+ break;
+ case "--restrict-permissions":
+ sessionParams.installFlags &=
+ ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
break;
case "--dont-kill":
sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
@@ -3004,10 +3005,10 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" -d: allow version code downgrade (debuggable packages only)");
pw.println(" -p: partial application install (new split on top of existing pkg)");
pw.println(" -g: grant all runtime permissions");
- pw.println(" -w: whitelist all restricted permissions");
pw.println(" -S: size in bytes of package, required for stdin");
pw.println(" --user: install under the given user.");
pw.println(" --dont-kill: installing a new feature split, don't kill running app");
+ pw.println(" --restrict-permissions: don't whitelist restricted permissions at install");
pw.println(" --originating-uri: set URI where app was downloaded from");
pw.println(" --referrer: set URI that instigated the install of the app");
pw.println(" --pkg: specify expected package name of app being installed");
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 9782648efb6b..eec4b70880a5 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -680,20 +680,23 @@ class ShortcutPackage extends ShortcutPackageItem {
final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
for (int i = 0; i < shortcuts.size(); i++) {
- final ShortcutInfo si = shortcuts.get(i);
+ final Set<String> categories = shortcuts.get(i).getCategories();
+ if (categories == null || categories.isEmpty()) {
+ continue;
+ }
for (int j = 0; j < matchedTargets.size(); j++) {
// Shortcut must have all of share target categories
boolean hasAllCategories = true;
final ShareTargetInfo target = matchedTargets.get(j);
for (int q = 0; q < target.mCategories.length; q++) {
- if (!si.getCategories().contains(target.mCategories[q])) {
+ if (!categories.contains(target.mCategories[q])) {
hasAllCategories = false;
break;
}
}
if (hasAllCategories) {
- result.add(new ShortcutManager.ShareShortcutInfo(si, new ComponentName(
- getPackageName(), target.mTargetClass)));
+ result.add(new ShortcutManager.ShareShortcutInfo(shortcuts.get(i),
+ new ComponentName(getPackageName(), target.mTargetClass)));
break;
}
}
@@ -706,6 +709,45 @@ class ShortcutPackage extends ShortcutPackageItem {
}
/**
+ * Returns the number of shortcuts that can be used as a share target in the ShareSheet. Such
+ * shortcuts must have a matching category with at least one of the defined ShareTargets from
+ * the app's Xml resource.
+ */
+ int getSharingShortcutCount() {
+ if (mShortcuts.isEmpty() || mShareTargets.isEmpty()) {
+ return 0;
+ }
+
+ // Get the list of all dynamic shortcuts in this package
+ final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+ findAll(shortcuts, ShortcutInfo::isDynamicVisible, ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+ int sharingShortcutCount = 0;
+ for (int i = 0; i < shortcuts.size(); i++) {
+ final Set<String> categories = shortcuts.get(i).getCategories();
+ if (categories == null || categories.isEmpty()) {
+ continue;
+ }
+ for (int j = 0; j < mShareTargets.size(); j++) {
+ // A SharingShortcut must have all of share target categories
+ boolean hasAllCategories = true;
+ final ShareTargetInfo target = mShareTargets.get(j);
+ for (int q = 0; q < target.mCategories.length; q++) {
+ if (!categories.contains(target.mCategories[q])) {
+ hasAllCategories = false;
+ break;
+ }
+ }
+ if (hasAllCategories) {
+ sharingShortcutCount++;
+ break;
+ }
+ }
+ }
+ return sharingShortcutCount;
+ }
+
+ /**
* Return the filenames (excluding path names) of icon bitmap files from this package.
*/
public ArraySet<String> getUsedBitmapFiles() {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index daef4e064004..2d8a2acd575f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -95,6 +95,7 @@ import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -413,6 +414,9 @@ public class ShortcutService extends IShortcutService.Stub {
@GuardedBy("mLock")
private Exception mLastWtfStacktrace;
+ @GuardedBy("mLock")
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
static class InvalidFileFormatException extends Exception {
public InvalidFileFormatException(String message, Throwable cause) {
super(message, cause);
@@ -981,6 +985,8 @@ public class ShortcutService extends IShortcutService.Stub {
Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
file.failWrite(os);
}
+
+ getUserShortcutsLocked(userId).logSharingShortcutStats(mMetricsLogger);
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 1fd9b69e521d..8c207a8e1a6f 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.pm.ShortcutManager;
+import android.metrics.LogMaker;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
@@ -27,6 +28,8 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.InvalidFileFormatException;
@@ -647,4 +650,23 @@ class ShortcutUser {
return result;
}
+
+ void logSharingShortcutStats(MetricsLogger logger) {
+ int packageWithShareTargetsCount = 0;
+ int totalSharingShortcutCount = 0;
+ for (int i = 0; i < mPackages.size(); i++) {
+ if (mPackages.valueAt(i).hasShareTargets()) {
+ packageWithShareTargetsCount++;
+ totalSharingShortcutCount += mPackages.valueAt(i).getSharingShortcutCount();
+ }
+ }
+
+ final LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_SHORTCUTS_CHANGED);
+ logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_USER_ID)
+ .setSubtype(mUserId));
+ logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_PACKAGE_COUNT)
+ .setSubtype(packageWithShareTargetsCount));
+ logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_SHORTCUT_COUNT)
+ .setSubtype(totalSharingShortcutCount));
+ }
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e0256460042a..4fdf1bc58e05 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1134,7 +1134,7 @@ public final class DefaultPermissionGrantPolicy {
private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissionsWithoutSplits,
boolean systemFixed, boolean ignoreSystemPackage,
boolean whitelistRestrictedPermissions, int userId) {
- UserHandle user = UserHandle.of(userId);
+ UserHandle user = UserHandle.of(userId);
if (pkg == null) {
return;
}
@@ -1203,7 +1203,7 @@ public final class DefaultPermissionGrantPolicy {
if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) {
return;
}
- if (!requestedPermissions.equals(disabledPkg.requestedPermissions)) {
+ if (!Arrays.equals(requestedPermissions, disabledPkg.requestedPermissions)) {
grantablePermissions = new ArraySet<>(Arrays.asList(requestedPermissions));
requestedPermissions = disabledPkg.requestedPermissions;
}
@@ -1213,7 +1213,7 @@ public final class DefaultPermissionGrantPolicy {
final int numRequestedPermissions = requestedPermissions.length;
// Sort requested permissions so that all permissions that are a foreground permission (i.e.
- // permisions that have background permission) are before their background permissions.
+ // permissions that have a background permission) are before their background permissions.
final String[] sortedRequestedPermissions = new String[numRequestedPermissions];
int numForeground = 0;
int numOther = 0;
@@ -1258,9 +1258,16 @@ public final class DefaultPermissionGrantPolicy {
continue;
}
- int uid = UserHandle.getUid(userId,
- UserHandle.getAppId(pkg.applicationInfo.uid));
- String op = AppOpsManager.permissionToOp(permission);
+ // Preserve whitelisting flags.
+ newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
+
+ // If we are whitelisting the permission, update the exempt flag before grant.
+ if (whitelistRestrictedPermissions && isPermissionRestricted(permission)) {
+ mContext.getPackageManager().updatePermissionFlags(permission,
+ pkg.packageName,
+ PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
+ PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
+ }
if (pm.checkPermission(permission, pkg.packageName)
!= PackageManager.PERMISSION_GRANTED) {
@@ -1268,13 +1275,12 @@ public final class DefaultPermissionGrantPolicy {
.grantRuntimePermission(pkg.packageName, permission, user);
}
- if (whitelistRestrictedPermissions && isPermissionRestricted(permission)) {
- newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- }
-
mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
newFlags, newFlags, user);
+ int uid = UserHandle.getUid(userId,
+ UserHandle.getAppId(pkg.applicationInfo.uid));
+
List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
.get(permission);
if (fgPerms != null) {
@@ -1285,6 +1291,7 @@ public final class DefaultPermissionGrantPolicy {
if (pm.checkPermission(fgPerm, pkg.packageName)
== PackageManager.PERMISSION_GRANTED) {
// Upgrade the app-op state of the fg permission to allow bg access
+ // TODO: Dont' call app ops from package manager code.
mContext.getSystemService(AppOpsManager.class).setUidMode(
AppOpsManager.permissionToOp(fgPerm), uid,
AppOpsManager.MODE_ALLOWED);
@@ -1295,8 +1302,10 @@ public final class DefaultPermissionGrantPolicy {
}
String bgPerm = getBackgroundPermission(permission);
+ String op = AppOpsManager.permissionToOp(permission);
if (bgPerm == null) {
if (op != null) {
+ // TODO: Dont' call app ops from package manager code.
mContext.getSystemService(AppOpsManager.class).setUidMode(op, uid,
AppOpsManager.MODE_ALLOWED);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 448e595014bc..37c1aaa45b8b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -32,7 +32,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTAL
import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM;
import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE;
import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
-import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
@@ -333,22 +332,15 @@ public class PermissionManagerService {
mPackageManagerInt.getInstantAppPackageName(uid) != null;
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
- PermissionManager.addPermissionDenialHint("User does not exist. userId=" + userId);
return PackageManager.PERMISSION_DENIED;
}
if (pkg != null) {
if (pkg.mSharedUserId != null) {
if (isCallerInstantApp) {
- PermissionManager.addPermissionDenialHint(
- "Caller is instant app. Pkg is shared. callingUid=" + callingUid
- + " pkg=" + pkg.packageName);
return PackageManager.PERMISSION_DENIED;
}
} else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
- PermissionManager.addPermissionDenialHint(
- "Access is filtered. pkg=" + pkg + " callingUid=" + callingUid
- + " callingUserId=" + callingUserId);
return PackageManager.PERMISSION_DENIED;
}
final PermissionsState permissionsState =
@@ -358,8 +350,6 @@ public class PermissionManagerService {
if (mSettings.isPermissionInstant(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
- PermissionManager.addPermissionDenialHint(
- "Caller instant app, but perm is not instant");
} else {
return PackageManager.PERMISSION_GRANTED;
}
@@ -367,7 +357,6 @@ public class PermissionManagerService {
if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
- PermissionManager.addPermissionDenialHint("Does not have permission " + permName);
} else {
ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms != null) {
@@ -379,8 +368,6 @@ public class PermissionManagerService {
return PackageManager.PERMISSION_GRANTED;
}
}
- PermissionManager.addPermissionDenialHint(
- "System permissions do not contain " + permName);
}
return PackageManager.PERMISSION_DENIED;
}
@@ -1070,8 +1057,8 @@ public class PermissionManagerService {
boolean wasChanged = false;
- boolean restrictionExempt = !RESTRICTED_PERMISSIONS_ENABLED
- || (origPermissions.getPermissionFlags(bp.name, userId)
+ boolean restrictionExempt =
+ (origPermissions.getPermissionFlags(bp.name, userId)
& FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
boolean restrictionApplied = (origPermissions.getPermissionFlags(
bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
@@ -1189,8 +1176,8 @@ public class PermissionManagerService {
for (int userId : currentUserIds) {
boolean wasChanged = false;
- boolean restrictionExempt = !RESTRICTED_PERMISSIONS_ENABLED
- || (origPermissions.getPermissionFlags(bp.name, userId)
+ boolean restrictionExempt =
+ (origPermissions.getPermissionFlags(bp.name, userId)
& FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
boolean restrictionApplied = (origPermissions.getPermissionFlags(
bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
@@ -2066,7 +2053,7 @@ public class PermissionManagerService {
return;
}
- if (RESTRICTED_PERMISSIONS_ENABLED && bp.isHardOrSoftRestricted()
+ if (bp.isHardOrSoftRestricted()
&& (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
Log.e(TAG, "Cannot grant restricted non-exempt permission "
+ permName + " for package " + packageName);
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index a280d83fac27..250f3313e3c4 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -326,8 +326,8 @@ public final class PermissionPolicyService extends SystemService {
return;
}
- final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED
- && (mPackageManager.getPermissionFlags(permission, pkg.packageName,
+ final boolean applyRestriction =
+ (mPackageManager.getPermissionFlags(permission, pkg.packageName,
mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
if (permissionInfo.isHardRestricted()) {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 9decb58aff2e..feef5e27d26a 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -326,7 +326,7 @@ class ActivityMetricsLogger {
intent));
}
- if (!isAnyTransitionActive()) {
+ if (mCurrentTransitionStartTime == INVALID_START_TIME) {
mCurrentTransitionStartTime = SystemClock.uptimeMillis();
mLastTransitionStartTime = mCurrentTransitionStartTime;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 802683a67f80..39eda044a5b3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2322,7 +2322,9 @@ final class ActivityRecord extends ConfigurationContainer {
return;
}
- if (configChanges == 0 && mAppWindowToken.okToDisplay()) {
+ // Window configuration changes only effect windows, so don't require a screen freeze.
+ int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION);
+ if (freezableConfigChanges == 0 && mAppWindowToken.okToDisplay()) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + appToken);
return;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 4a6aa336e36f..b234bc6f77c3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -141,6 +141,7 @@ import android.app.IActivityTaskManager;
import android.app.IApplicationThread;
import android.app.IAssistDataReceiver;
import android.app.INotificationManager;
+import android.app.IRequestFinishCallback;
import android.app.ITaskStackListener;
import android.app.Notification;
import android.app.NotificationManager;
@@ -2288,6 +2289,32 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ @Override
+ public void onBackPressedOnTaskRoot(IBinder token, IRequestFinishCallback callback) {
+ synchronized (mGlobalLock) {
+ ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ ActivityStack stack = r.getActivityStack();
+ if (stack != null && stack.isSingleTaskInstance()) {
+ // Single-task stacks are used for activities which are presented in floating
+ // windows above full screen activities. Instead of directly finishing the
+ // task, a task change listener is used to notify SystemUI so the action can be
+ // handled specially.
+ final TaskRecord task = r.getTaskRecord();
+ mTaskChangeNotificationController
+ .notifyBackPressedOnTaskRoot(task.getTaskInfo());
+ } else {
+ try {
+ callback.requestFinish();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to invoke request finish callback", e);
+ }
+ }
+ }
+ }
+
/**
* TODO: Add mController hook
*/
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 649949701419..fd90f0339e63 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -509,6 +509,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
final DisplayContent displayContent = getDisplayContent();
displayContent.mOpeningApps.remove(this);
displayContent.mClosingApps.remove(this);
+ if (isInChangeTransition()) {
+ clearChangeLeash(getPendingTransaction(), true /* cancel */);
+ }
+ displayContent.mChangingApps.remove(this);
waitingToShow = false;
hiddenRequested = !visible;
mDeferHidingClient = deferHidingClient;
@@ -1310,7 +1314,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
void onDisplayChanged(DisplayContent dc) {
DisplayContent prevDc = mDisplayContent;
super.onDisplayChanged(dc);
- if (prevDc == null) {
+ if (prevDc == null || prevDc == mDisplayContent) {
return;
}
if (prevDc.mChangingApps.contains(this)) {
@@ -1333,7 +1337,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
- if (prevDc != mDisplayContent && mLetterbox != null) {
+ if (mLetterbox != null) {
mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index b6295e194aac..b8504db8e810 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -70,6 +70,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -2007,7 +2008,8 @@ public class DisplayPolicy {
pf.set(displayFrames.mOverscan);
} else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
- || type == TYPE_VOLUME_OVERLAY)) {
+ || type == TYPE_VOLUME_OVERLAY
+ || type == TYPE_KEYGUARD_DIALOG)) {
// Asking for layout as if the nav bar is hidden, lets the application
// extend into the unrestricted overscan screen area. We only do this for
// application windows and certain system windows to ensure no window that
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 3d57219209d7..66200e39938b 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -53,6 +53,7 @@ class TaskChangeNotificationController {
private static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG = 18;
private static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED_MSG = 19;
private static final int NOTIFY_SIZE_COMPAT_MODE_ACTIVITY_CHANGED_MSG = 20;
+ private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -92,6 +93,10 @@ class TaskChangeNotificationController {
l.onTaskDescriptionChanged((RunningTaskInfo) m.obj);
};
+ private final TaskStackConsumer mNotifyBackPressedOnTaskRoot = (l, m) -> {
+ l.onBackPressedOnTaskRoot((RunningTaskInfo) m.obj);
+ };
+
private final TaskStackConsumer mNotifyActivityRequestedOrientationChanged = (l, m) -> {
l.onActivityRequestedOrientationChanged(m.arg1, m.arg2);
};
@@ -225,6 +230,9 @@ class TaskChangeNotificationController {
case NOTIFY_SIZE_COMPAT_MODE_ACTIVITY_CHANGED_MSG:
forAllRemoteListeners(mOnSizeCompatModeActivityChanged, msg);
break;
+ case NOTIFY_BACK_PRESSED_ON_TASK_ROOT:
+ forAllRemoteListeners(mNotifyBackPressedOnTaskRoot, msg);
+ break;
}
}
}
@@ -458,4 +466,15 @@ class TaskChangeNotificationController {
forAllLocalListeners(mOnSizeCompatModeActivityChanged, msg);
msg.sendToTarget();
}
+
+ /**
+ * Notify listeners that an activity received a back press when there are no other activities
+ * in the back stack.
+ */
+ void notifyBackPressedOnTaskRoot(TaskInfo taskInfo) {
+ final Message msg = mHandler.obtainMessage(NOTIFY_BACK_PRESSED_ON_TASK_ROOT,
+ taskInfo);
+ forAllLocalListeners(mNotifyBackPressedOnTaskRoot, msg);
+ msg.sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eac771639688..088d2f0fd288 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -137,6 +137,7 @@ import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Matrix;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -2604,9 +2605,11 @@ public class WindowManagerService extends IWindowManager.Stub
final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken != null) {
final WindowState win = wtoken.findMainWindow();
- if (win != null) {
- win.mWinAnimator.setOpaqueLocked(isOpaque);
+ if (win == null) {
+ return;
}
+ isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format);
+ win.mWinAnimator.setOpaqueLocked(isOpaque);
}
}
@@ -6828,9 +6831,26 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ int lastWindowingMode = displayContent.getWindowingMode();
mDisplayWindowSettings.setWindowingModeLocked(displayContent, mode);
reconfigureDisplayLocked(displayContent);
+
+ if (lastWindowingMode != displayContent.getWindowingMode()) {
+ // reconfigure won't detect this change in isolation because the windowing mode is
+ // already set on the display, so fire off a new config now.
+ mH.removeMessages(H.SEND_NEW_CONFIGURATION);
+
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ // direct call since lock is shared.
+ sendNewConfiguration(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ // Now that all configurations are updated, execute pending transitions
+ displayContent.executeAppTransition();
+ }
}
}
@@ -7415,8 +7435,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean shouldShowIme(int displayId) {
synchronized (mGlobalLock) {
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- return mDisplayWindowSettings.shouldShowImeLocked(displayContent);
+ return WindowManagerService.this.shouldShowIme(displayId);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3834d57c3525..dd3c6004dcad 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1078,7 +1078,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ mRequestedWidth + ", mRequestedheight="
+ mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
+ "): frame=" + mWindowFrames.mFrame.toShortString()
- + " " + mWindowFrames.getInsetsInfo());
+ + " " + mWindowFrames.getInsetsInfo()
+ + " " + mAttrs.getTitle());
}
// TODO: Look into whether this override is still necessary.
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 89a1ec8507d6..da175792268f 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1495,7 +1495,8 @@ struct GnssBatchingCallback_V2_0 : public IGnssBatchingCallback_V2_0 {
}
};
-static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+/* Initializes the GNSS service handle. */
+static void android_location_GnssLocationProvider_set_gps_service_handle() {
gnssHal_V2_0 = IGnss_V2_0::getService();
if (gnssHal_V2_0 != nullptr) {
gnssHal = gnssHal_V2_0;
@@ -1514,7 +1515,12 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
gnssHal = IGnss_V1_0::getService();
}
-static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass clazz) {
+/* One time initialization at system boot */
+static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+ // Initialize the top level gnss HAL handle.
+ android_location_GnssLocationProvider_set_gps_service_handle();
+
+ // Cache methodIDs and class IDs.
method_reportLocation = env->GetMethodID(clazz, "reportLocation",
"(ZLandroid/location/Location;)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
@@ -1638,7 +1644,11 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass
(jclass) env->NewGlobalRef(gnssConfiguration_halInterfaceVersionClass);
method_halInterfaceVersionCtor =
env->GetMethodID(class_gnssConfiguration_halInterfaceVersion, "<init>", "(II)V");
+}
+/* Initialization needed at system boot and whenever GNSS service dies. */
+static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass clazz,
+ jboolean reinitializeGnssServiceHandle) {
/*
* Save a pointer to JVM.
*/
@@ -1647,6 +1657,10 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass
LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus);
}
+ if (reinitializeGnssServiceHandle) {
+ android_location_GnssLocationProvider_set_gps_service_handle();
+ }
+
if (gnssHal == nullptr) {
ALOGE("Unable to get GPS service\n");
return;
@@ -1871,6 +1885,7 @@ static jobject android_location_GnssConfiguration_get_gnss_configuration_version
return createHalInterfaceVersionJavaObject(env, major, minor);
}
+/* Initialization needed each time the GPS service is shutdown. */
static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) {
/*
* This must be set before calling into the HAL library.
@@ -3026,7 +3041,7 @@ static const JNINativeMethod sMethods[] = {
android_location_GnssLocationProvider_class_init_native)},
{"native_is_supported", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_is_supported)},
- {"native_init_once", "()V", reinterpret_cast<void *>(
+ {"native_init_once", "(Z)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_init_once)},
{"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
{"native_cleanup", "()V", reinterpret_cast<void *>(
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
new file mode 100644
index 000000000000..4538cacbf9c4
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.color;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.DisplayPrimaries;
+import android.view.SurfaceControl.CieXyz;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+@RunWith(AndroidJUnit4.class)
+public class DisplayWhiteBalanceTintControllerTest {
+ @Mock
+ private Context mMockedContext;
+ @Mock
+ private Resources mMockedResources;
+
+ private MockitoSession mSession;
+ private Resources mResources;
+ IBinder mDisplayToken;
+ DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController;
+
+ @Before
+ public void setUp() {
+ mSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .mockStatic(SurfaceControl.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mResources = InstrumentationRegistry.getContext().getResources();
+ // These Resources are common to all tests.
+ doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin))
+ .when(mMockedResources)
+ .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin);
+ doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax))
+ .when(mMockedResources)
+ .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax);
+ doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault))
+ .when(mMockedResources)
+ .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+ doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite))
+ .when(mMockedResources)
+ .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ doReturn(mMockedResources).when(mMockedContext).getResources();
+
+ mDisplayToken = new Binder();
+ doReturn(mDisplayToken).when(() -> SurfaceControl.getInternalDisplayToken());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mSession != null) {
+ mSession.finishMocking();
+ }
+ }
+
+ /**
+ * Setup should succeed when SurfaceControl setup results in a valid color transform.
+ */
+ @Test
+ public void displayWhiteBalance_setupWithSurfaceControl() {
+ // Make SurfaceControl return sRGB primaries
+ DisplayPrimaries displayPrimaries = new DisplayPrimaries();
+ displayPrimaries.red = new CieXyz();
+ displayPrimaries.red.X = 0.412315f;
+ displayPrimaries.red.Y = 0.212600f;
+ displayPrimaries.red.Z = 0.019327f;
+ displayPrimaries.green = new CieXyz();
+ displayPrimaries.green.X = 0.357600f;
+ displayPrimaries.green.Y = 0.715200f;
+ displayPrimaries.green.Z = 0.119200f;
+ displayPrimaries.blue = new CieXyz();
+ displayPrimaries.blue.X = 0.180500f;
+ displayPrimaries.blue.Y = 0.072200f;
+ displayPrimaries.blue.Z = 0.950633f;
+ displayPrimaries.white = new CieXyz();
+ displayPrimaries.white.X = 0.950456f;
+ displayPrimaries.white.Y = 1.000000f;
+ displayPrimaries.white.Z = 1.089058f;
+ doReturn(displayPrimaries)
+ .when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));
+
+ setUpTintController();
+ assertWithMessage("Setup with valid SurfaceControl failed")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isTrue();
+ }
+
+ /**
+ * Setup should fail when SurfaceControl setup results in an invalid color transform.
+ */
+ @Test
+ public void displayWhiteBalance_setupWithInvalidSurfaceControlData() {
+ // Make SurfaceControl return invalid display primaries
+ DisplayPrimaries displayPrimaries = new DisplayPrimaries();
+ displayPrimaries.red = new CieXyz();
+ displayPrimaries.green = new CieXyz();
+ displayPrimaries.blue = new CieXyz();
+ displayPrimaries.white = new CieXyz();
+ doReturn(displayPrimaries)
+ .when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));
+
+ setUpTintController();
+ assertWithMessage("Setup with invalid SurfaceControl succeeded")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isFalse();
+ }
+
+ /**
+ * Setup should succeed when SurfaceControl setup fails and Resources result in a valid color
+ * transform.
+ */
+ @Test
+ public void displayWhiteBalance_setupWithResources() {
+ // Use default (valid) Resources
+ doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries))
+ .when(mMockedResources)
+ .getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries);
+ // Make SurfaceControl setup fail
+ doReturn(null).when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));
+
+ setUpTintController();
+ assertWithMessage("Setup with valid Resources failed")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isTrue();
+ }
+
+ /**
+ * Setup should fail when SurfaceControl setup fails and Resources result in an invalid color
+ * transform.
+ */
+ @Test
+ public void displayWhiteBalance_setupWithInvalidResources() {
+ // Use Resources with invalid color data
+ doReturn(new String[] {
+ "0", "0", "0", // Red X, Y, Z
+ "0", "0", "0", // Green X, Y, Z
+ "0", "0", "0", // Blue X, Y, Z
+ "0", "0", "0", // White X, Y, Z
+ })
+ .when(mMockedResources)
+ .getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries);
+ // Make SurfaceControl setup fail
+ doReturn(null).when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));
+
+ setUpTintController();
+ assertWithMessage("Setup with invalid Resources succeeded")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isFalse();
+ }
+
+ private void setUpTintController() {
+ mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController();
+ mDisplayWhiteBalanceTintController.setUp(mMockedContext, true);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index de841a0ac4ec..8bb8aae76849 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -1029,6 +1029,34 @@ public class ColorDisplayServiceTest {
assertDwbActive(true);
}
+ @Test
+ public void displayWhiteBalance_disabledWhileAccessibilityColorCorrectionEnabled() {
+ setDisplayWhiteBalanceEnabled(true);
+ startService();
+ setAccessibilityColorCorrection(true);
+
+ mCds.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(false);
+
+ setAccessibilityColorCorrection(false);
+ mCds.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_disabledWhileAccessibilityColorInversionEnabled() {
+ setDisplayWhiteBalanceEnabled(true);
+ startService();
+ setAccessibilityColorInversion(true);
+
+ mCds.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(false);
+
+ setAccessibilityColorInversion(false);
+ mCds.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(true);
+ }
+
/**
* Configures Night display to use a custom schedule.
*
diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 1dd4e1579866..4ef156e239d3 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -18,6 +18,11 @@ package com.android.server.display.color;
import static com.google.common.truth.Truth.assertWithMessage;
+import androidx.test.InstrumentationRegistry;
+
+import java.lang.System;
+import java.util.Arrays;
+
import org.junit.Before;
import org.junit.Test;
@@ -28,6 +33,8 @@ public class DisplayWhiteBalanceTintControllerTest {
@Before
public void setUp() {
mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController();
+ mDisplayWhiteBalanceTintController.setUp(InstrumentationRegistry.getContext(), true);
+ mDisplayWhiteBalanceTintController.setActivated(true);
}
@Test
@@ -59,4 +66,31 @@ public class DisplayWhiteBalanceTintControllerTest {
.isEqualTo(colorTemperature);
}
+ @Test
+ public void displayWhiteBalance_setMatrixValidDwbCalculation() {
+ float[] currentMatrix = mDisplayWhiteBalanceTintController.getMatrix();
+ float[] oldMatrix = Arrays.copyOf(currentMatrix, currentMatrix.length);
+
+ mDisplayWhiteBalanceTintController
+ .setMatrix(mDisplayWhiteBalanceTintController.mCurrentColorTemperature + 1);
+ assertWithMessage("DWB matrix did not change when setting a new temperature")
+ .that(Arrays.equals(oldMatrix, currentMatrix))
+ .isFalse();
+ }
+
+ @Test
+ public void displayWhiteBalance_setMatrixInvalidDwbCalculation() {
+ Arrays.fill(mDisplayWhiteBalanceTintController.mDisplayNominalWhiteXYZ, 0);
+ mDisplayWhiteBalanceTintController
+ .setMatrix(mDisplayWhiteBalanceTintController.mCurrentColorTemperature + 1);
+ assertWithMessage("DWB matrix not set to identity after an invalid DWB calculation")
+ .that(Arrays.equals(mDisplayWhiteBalanceTintController.getMatrix(),
+ new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ })
+ ).isTrue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 6845f15f6a28..b806180a8584 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1584,6 +1584,22 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
/**
+ * Make a shortcut with an ID and Category.
+ */
+ protected ShortcutInfo makeShortcutWithCategory(String id, Set<String> categories) {
+ final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
+ .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
+ .setShortLabel("title-" + id)
+ .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class))
+ .setCategories(categories);
+ final ShortcutInfo s = b.build();
+
+ s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
+
+ return s;
+ }
+
+ /**
* Make an intent.
*/
protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
@@ -1818,6 +1834,17 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
/**
+ * @return the number of shortcuts stored internally for the caller that can be used as a share
+ * target in the ShareSheet. Such shortcuts have a matching category with at least one of the
+ * defined ShareTargets from the app's Xml resource.
+ */
+ protected int getCallerSharingShortcutCount() {
+ final ShortcutPackage p = mService.getPackageShortcutForTest(
+ getCallingPackage(), getCallingUserId());
+ return p == null ? 0 : p.getSharingShortcutCount();
+ }
+
+ /**
* @return all shortcuts owned by caller that are actually visible via ShortcutManager.
* See also {@link #getCallerShortcuts}.
*/
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
index eb4db7a0f4af..ba26f7930dcb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
@@ -17,6 +17,7 @@ package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
import android.content.ComponentName;
import android.content.pm.ShortcutInfo;
@@ -25,6 +26,8 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.frameworks.servicestests.R;
import com.android.server.pm.ShortcutService.ConfigConstants;
+import java.util.Set;
+
/**
* Tests related to shortcut rank auto-adjustment.
*/
@@ -50,6 +53,10 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
return makeShortcutWithActivityAndRank(id, activity, ShortcutInfo.RANK_NOT_SET);
}
+ private ShortcutInfo shortcut(String id, Set<String> categories) {
+ return makeShortcutWithCategory(id, categories);
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -502,4 +509,30 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
runTestWithManifestShortcuts(() -> testDisableShortcuts_noManifestShortcuts());
}
+ public void testGetSharingShortcutCount() {
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_share_targets);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ // There are two valid <share-target> definitions in the test manifest with two different
+ // categories: {"com.test.category.CATEGORY1", "com.test.category.CATEGORY2"} and
+ // {"com.test.category.CATEGORY5", "com.test.category.CATEGORY6"}.
+ //
+ // Note that a shortcut is a match, only if it has ALL of the categories of at least one
+ // of the share-target definitions from the manifest.
+
+ mManager.addDynamicShortcuts(list(
+ shortcut("s1", set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2")),
+ shortcut("s2", set("com.test.category.CATEGORY5")),
+ shortcut("s3", set("com.test.category.CATEGORY5", "com.test.category.CATEGORY6")),
+ shortcut("s4", set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2",
+ "com.test.category.CATEGORY5", "com.test.category.CATEGORY6")),
+ shortcut("s5", A1)
+ ));
+
+ assertEquals(3, getCallerSharingShortcutCount());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 777e4f4915b8..035568f489be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -158,4 +158,22 @@ public class AppChangeTransitionTests extends WindowTestsBase {
waitUntilHandlersIdle();
mToken.removeImmediately();
}
+
+ @Test
+ public void testCancelPendingChangeOnHide() {
+ // setup currently defaults to no snapshot.
+ setUpOnDisplay(mDisplayContent);
+
+ mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(1, mDisplayContent.mChangingApps.size());
+ assertTrue(mToken.isInChangeTransition());
+
+ // Changing visibility should cancel the change transition and become closing
+ mToken.setVisibility(false, false);
+ assertEquals(0, mDisplayContent.mChangingApps.size());
+ assertFalse(mToken.isInChangeTransition());
+
+ waitUntilHandlersIdle();
+ mToken.removeImmediately();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index e90f094636f7..4a87aa46db58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -21,6 +21,7 @@ import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -32,6 +33,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
@@ -160,6 +162,25 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
@Test
+ public void layoutWindowLw_keyguardDialog_hideNav() {
+ synchronized (mWm.mGlobalLock) {
+ mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
+ mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null /* attached */, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ }
+ }
+
+ @Test
public void layoutWindowLw_withDisplayCutout() {
synchronized (mWm.mGlobalLock) {
addDisplayCutout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 652ea7d32953..336fa041dea8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -51,6 +51,7 @@ import android.view.Surface;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
import org.junit.After;
@@ -588,6 +589,23 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
getStoredDisplayAttributeValue("shouldShowIme"));
}
+ @Test
+ public void testShouldShowImeWithinForceDesktopMode() {
+ try {
+ // Presume display enabled force desktop mode from developer options.
+ final DisplayContent dc = createMockSimulatedDisplay();
+ mWm.setForceDesktopModeOnExternalDisplays(true);
+ final WindowManagerInternal wmInternal = LocalServices.getService(
+ WindowManagerInternal.class);
+ // Make sure WindowManagerInter#shouldShowIme as true is due to
+ // mForceDesktopModeOnExternalDisplays as true.
+ assertFalse(mWm.mDisplayWindowSettings.shouldShowImeLocked(dc));
+ assertTrue(wmInternal.shouldShowIme(dc.getDisplayId()));
+ } finally {
+ mWm.setForceDesktopModeOnExternalDisplays(false);
+ }
+ }
+
/**
* Prepares display settings and stores in {@link #mStorage}. Uses provided display identifier
* and stores windowingMode=WINDOWING_MODE_PINNED.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 8c37ca5e309e..3a702cb9521c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.os.Process.SYSTEM_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.View.VISIBLE;
@@ -445,4 +446,13 @@ class WindowTestsBase {
return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
}
}
+
+ /** Creates a {@link DisplayContent} as parts of simulate display info for test. */
+ DisplayContent createMockSimulatedDisplay() {
+ DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.copyFrom(mDisplayInfo);
+ displayInfo.type = Display.TYPE_VIRTUAL;
+ displayInfo.ownerUid = SYSTEM_UID;
+ return createNewDisplay(displayInfo);
+ }
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 63d427a6f3c4..6a71c4fa74b3 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -337,12 +337,12 @@ public final class SmsManager {
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/);
+ true /* persistMessage*/, ActivityThread.currentPackageName());
}
private void sendTextMessageInternal(String destinationAddress, String scAddress,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
- boolean persistMessage) {
+ boolean persistMessage, String packageName) {
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException("Invalid destinationAddress");
}
@@ -355,9 +355,8 @@ public final class SmsManager {
// If the subscription is invalid or default, we will use the default phone to send the
// SMS and possibly fail later in the SMS sending process.
ISms iSms = getISmsServiceOrThrow();
- iSms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
- destinationAddress,
- scAddress, text, sentIntent, deliveryIntent,
+ iSms.sendTextForSubscriber(getSubscriptionId(), packageName,
+ destinationAddress, scAddress, text, sentIntent, deliveryIntent,
persistMessage);
} catch (RemoteException ex) {
// ignore it
@@ -389,7 +388,7 @@ public final class SmsManager {
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */);
+ false /* persistMessage */, ActivityThread.currentPackageName());
}
/**
@@ -630,13 +629,30 @@ public final class SmsManager {
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/);
+ deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName());
+ }
+
+ /**
+ * @hide
+ * Similar method as #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
+ * With an additional argument
+ * @param packageName serves as the default package name if ActivityThread.currentpackageName is
+ * null.
+ */
+ public void sendMultipartTextMessageExternal(
+ String destinationAddress, String scAddress, ArrayList<String> parts,
+ ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
+ String packageName) {
+ sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
+ deliveryIntents, true /* persistMessage*/,
+ ActivityThread.currentPackageName() == null
+ ? packageName : ActivityThread.currentPackageName());
}
private void sendMultipartTextMessageInternal(
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
- boolean persistMessage) {
+ boolean persistMessage, String packageName) {
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException("Invalid destinationAddress");
}
@@ -648,8 +664,7 @@ public final class SmsManager {
try {
ISms iSms = getISmsServiceOrThrow();
iSms.sendMultipartTextForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
- destinationAddress, scAddress, parts,
+ packageName, destinationAddress, scAddress, parts,
sentIntents, deliveryIntents, persistMessage);
} catch (RemoteException ex) {
// ignore it
@@ -663,8 +678,8 @@ public final class SmsManager {
if (deliveryIntents != null && deliveryIntents.size() > 0) {
deliveryIntent = deliveryIntents.get(0);
}
- sendTextMessage(destinationAddress, scAddress, parts.get(0),
- sentIntent, deliveryIntent);
+ sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
+ sentIntent, deliveryIntent, true, packageName);
}
}
@@ -685,7 +700,7 @@ public final class SmsManager {
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/);
+ deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName());
}
/**
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 9a8d7cd35cb0..785d7aea2a6f 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -140,10 +140,6 @@ public class UiccSlotInfo implements Parcelable {
return mIsEuicc;
}
- /**
- * Returns the ICCID of a the UICC in the given slot, or the EID if it is an eUICC. Note that if
- * the value is unavailble this will return null.
- */
public String getCardId() {
return mCardId;
}
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 22f078fc0c05..7b5145740b08 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -558,6 +558,24 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
} else if (this.getDisplayPriorityScore()
< emergencyNumber.getDisplayPriorityScore()) {
return 1;
+ } else if (this.getNumber().compareTo(emergencyNumber.getNumber()) != 0) {
+ return this.getNumber().compareTo(emergencyNumber.getNumber());
+ } else if (this.getCountryIso().compareTo(emergencyNumber.getCountryIso()) != 0) {
+ return this.getCountryIso().compareTo(emergencyNumber.getCountryIso());
+ } else if (this.getMnc().compareTo(emergencyNumber.getMnc()) != 0) {
+ return this.getMnc().compareTo(emergencyNumber.getMnc());
+ } else if (this.getEmergencyServiceCategoryBitmask()
+ != emergencyNumber.getEmergencyServiceCategoryBitmask()) {
+ return this.getEmergencyServiceCategoryBitmask()
+ > emergencyNumber.getEmergencyServiceCategoryBitmask() ? -1 : 1;
+ } else if (this.getEmergencyUrns().toString().compareTo(
+ emergencyNumber.getEmergencyUrns().toString()) != 0) {
+ return this.getEmergencyUrns().toString().compareTo(
+ emergencyNumber.getEmergencyUrns().toString());
+ } else if (this.getEmergencyCallRouting()
+ != emergencyNumber.getEmergencyCallRouting()) {
+ return this.getEmergencyCallRouting()
+ > emergencyNumber.getEmergencyCallRouting() ? -1 : 1;
} else {
return 0;
}
@@ -579,13 +597,9 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
if (emergencyNumberList == null) {
return;
}
- Set<EmergencyNumber> mergedEmergencyNumber = new HashSet<>();
+ Set<Integer> duplicatedEmergencyNumberPosition = new HashSet<>();
for (int i = 0; i < emergencyNumberList.size(); i++) {
- // Skip the check because it was merged.
- if (mergedEmergencyNumber.contains(emergencyNumberList.get(i))) {
- continue;
- }
- for (int j = i + 1; j < emergencyNumberList.size(); j++) {
+ for (int j = 0; j < i; j++) {
if (areSameEmergencyNumbers(
emergencyNumberList.get(i), emergencyNumberList.get(j))) {
Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: "
@@ -594,14 +608,15 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
emergencyNumberList.set(i, mergeSameEmergencyNumbers(
emergencyNumberList.get(i), emergencyNumberList.get(j)));
// Mark the emergency number has been merged
- mergedEmergencyNumber.add(emergencyNumberList.get(j));
+ duplicatedEmergencyNumberPosition.add(j);
}
}
}
- // Remove the marked emergency number in the orignal list
- for (int i = 0; i < emergencyNumberList.size(); i++) {
- if (mergedEmergencyNumber.contains(emergencyNumberList.get(i))) {
- emergencyNumberList.remove(i--);
+
+ // Remove the marked emergency number in the original list
+ for (int i = emergencyNumberList.size() - 1; i >= 0; i--) {
+ if (duplicatedEmergencyNumberPosition.contains(i)) {
+ emergencyNumberList.remove(i);
}
}
Collections.sort(emergencyNumberList);
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 326c88d47064..53372bff3e67 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -41,6 +41,7 @@ cc_defaults {
windows: {
enabled: true,
cflags: ["-Wno-maybe-uninitialized"],
+ ldflags: ["-static"],
},
darwin: {
cflags: ["-D_DARWIN_UNLIMITED_STREAMS"],
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index c4a1108ac62a..dbf51143f720 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -284,8 +284,58 @@ TEST(ResourcesValuesTest, AttributeIsCompatible) {
EXPECT_FALSE(attr_three.IsCompatibleWith(attr_one));
EXPECT_FALSE(attr_three.IsCompatibleWith(attr_two));
- EXPECT_FALSE(attr_three.IsCompatibleWith(attr_three));
+ EXPECT_TRUE(attr_three.IsCompatibleWith(attr_three));
EXPECT_FALSE(attr_three.IsCompatibleWith(attr_four));
+
+ EXPECT_FALSE(attr_four.IsCompatibleWith(attr_one));
+ EXPECT_FALSE(attr_four.IsCompatibleWith(attr_two));
+ EXPECT_FALSE(attr_four.IsCompatibleWith(attr_three));
+ EXPECT_TRUE(attr_four.IsCompatibleWith(attr_four));
+}
+
+TEST(ResourcesValuesTest, AttributeEnumIsCompatible) {
+ Attribute attr_one(TYPE_ENUM);
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
+
+ Attribute attr_two(TYPE_ENUM);
+ attr_two.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
+ attr_two.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
+ EXPECT_TRUE(attr_one.IsCompatibleWith(attr_two));
+}
+
+TEST(ResourcesValuesTest, DifferentAttributeEnumDifferentNameIsNotCompatible) {
+ Attribute attr_one(TYPE_ENUM);
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
+
+ Attribute attr_two(TYPE_ENUM);
+ attr_two.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/baz")), 0x07u});
+ EXPECT_FALSE(attr_one.IsCompatibleWith(attr_two));
+}
+
+TEST(ResourcesValuesTest, DifferentAttributeEnumDifferentValueIsNotCompatible) {
+ Attribute attr_one(TYPE_ENUM);
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
+ attr_one.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
+
+ Attribute attr_two(TYPE_ENUM);
+ attr_two.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
+ attr_two.symbols.push_back(
+ Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x09u});
+ EXPECT_FALSE(attr_one.IsCompatibleWith(attr_two));
}
} // namespace aapt
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index be9c84b3f8a6..78d42a160e21 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -408,54 +408,6 @@ TEST_F(TableMergerTest, FailToOverrideConflictingAttributeFormatsWithOverlay) {
ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/));
}
-TEST_F(TableMergerTest, FailToOverrideConflictingFlagsAndEnumsWithOverlay) {
- std::unique_ptr<ResourceTable> base =
- test::ResourceTableBuilder()
- .SetPackageId("", 0x7f)
- .AddValue("attr/foo", test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
- .Build())
- .Build();
-
- std::unique_ptr<ResourceTable> overlay =
- test::ResourceTableBuilder()
- .SetPackageId("", 0x7f)
- .AddValue("attr/foo", test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
- .SetWeak(false)
- .Build())
- .Build();
-
- ResourceTable final_table;
- TableMergerOptions options;
- options.auto_add_overlay = false;
- TableMerger merger(context_.get(), &final_table, options);
-
- ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
- ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/));
-
- base = test::ResourceTableBuilder()
- .SetPackageId("", 0x7f)
- .AddValue("attr/foo", test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_ENUM)
- .Build())
- .Build();
-
- overlay = test::ResourceTableBuilder()
- .SetPackageId("", 0x7f)
- .AddValue("attr/foo", test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_ENUM)
- .SetWeak(false)
- .Build())
- .Build();
-
- ResourceTable final_table2;
- TableMerger merger2(context_.get(), &final_table2, options);
-
- ASSERT_TRUE(merger2.Merge({}, base.get(), false /*overlay*/));
- ASSERT_FALSE(merger2.Merge({}, overlay.get(), true /*overlay*/));
-}
-
TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder().SetPackageId("", 0x7f).Build();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index a7793785fb9b..cd659e2a934a 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -93,7 +93,9 @@ import java.util.Map;
* {@link WifiP2pInfo} contains the address of the group owner
* {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
* if the current device is a p2p group owner. A p2p client can thus communicate with
- * the p2p group owner through a socket connection.
+ * the p2p group owner through a socket connection. If the current device is the p2p group owner,
+ * {@link WifiP2pInfo#groupOwnerAddress} is anonymized unless the caller holds the
+ * {@code android.Manifest.permission#LOCAL_MAC_ADDRESS} permission.
*
* <p> With peer discovery using {@link #discoverPeers}, an application discovers the neighboring
* peers, but has no good way to figure out which peer to establish a connection with. For example,
@@ -300,6 +302,11 @@ public class WifiP2pManager {
* To get information notifications on P2P getting enabled refers
* {@link #WIFI_P2P_STATE_ENABLED}.
*
+ * <p> The {@link #EXTRA_WIFI_P2P_DEVICE} extra contains an anonymized version of the device's
+ * MAC address. Callers holding the {@code android.Manifest.permission#LOCAL_MAC_ADDRESS}
+ * permission can use {@link #requestDeviceInfo} to obtain the actual MAC address of this
+ * device.
+ *
* All of these permissions are required to receive this broadcast:
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
* {@link android.Manifest.permission#ACCESS_WIFI_STATE}
@@ -1881,6 +1888,10 @@ public class WifiP2pManager {
* <p> This {@link android.net.wifi.p2p.WifiP2pDevice} is returned using the
* {@link DeviceInfoListener} listener.
*
+ * <p> {@link android.net.wifi.p2p.WifiP2pDevice#deviceAddress} is only available if the caller
+ * holds the {@code android.Manifest.permission#LOCAL_MAC_ADDRESS} permission, and holds the
+ * anonymized MAC address (02:00:00:00:00:00) otherwise.
+ *
* <p> This information is also included in the {@link #WIFI_P2P_THIS_DEVICE_CHANGED_ACTION}
* broadcast event with extra {@link #EXTRA_WIFI_P2P_DEVICE}.
*