summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/current.txt3
-rw-r--r--cmds/screencap/screencap.cpp3
-rw-r--r--cmds/statsd/Android.mk4
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp12
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h2
-rw-r--r--cmds/statsd/src/StatsService.cpp297
-rw-r--r--cmds/statsd/src/StatsService.h34
-rw-r--r--cmds/statsd/src/atoms.proto2
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp67
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h11
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp4
-rw-r--r--cmds/statsd/src/packages/UidMap.h2
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.cpp140
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.h100
-rw-r--r--cmds/statsd/src/shell/shell_config.proto36
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp25
-rw-r--r--cmds/statsd/src/storage/StorageManager.h4
-rw-r--r--core/java/android/app/ActivityManager.java8
-rw-r--r--core/java/android/app/ActivityManagerInternal.java18
-rw-r--r--core/java/android/app/DatePickerDialog.java2
-rw-r--r--core/java/android/app/IActivityManager.aidl3
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl5
-rw-r--r--core/java/android/app/UiModeManager.java9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java9
-rw-r--r--core/java/android/content/res/package.html4
-rw-r--r--core/java/android/hardware/camera2/utils/CloseableLock.java2
-rw-r--r--core/java/android/os/Binder.java2
-rw-r--r--core/java/android/os/Handler.java2
-rw-r--r--core/java/android/os/Looper.java2
-rw-r--r--core/java/android/os/Message.java24
-rw-r--r--core/java/android/os/ThreadLocalWorkSourceUid.java44
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java16
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java6
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java6
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java6
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java22
-rw-r--r--core/java/android/util/apk/ApkVerityBuilder.java160
-rw-r--r--core/java/android/view/IWindowManager.aidl5
-rw-r--r--core/java/android/view/SurfaceControl.java186
-rw-r--r--core/java/android/view/WindowManagerGlobal.java9
-rw-r--r--core/java/android/view/animation/DecelerateInterpolator.java4
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java44
-rw-r--r--core/java/android/webkit/TracingController.java2
-rw-r--r--core/java/com/android/internal/os/LooperStats.java55
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp1
-rw-r--r--core/jni/android_view_SurfaceControl.cpp117
-rw-r--r--core/proto/android/service/notification.proto3
-rw-r--r--core/res/res/xml/default_zen_mode_config.xml10
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java49
-rw-r--r--libs/hwui/CanvasTransform.cpp17
-rw-r--r--libs/hwui/CanvasTransform.h5
-rw-r--r--libs/hwui/RecordingCanvas.cpp78
-rw-r--r--libs/hwui/RecordingCanvas.h16
-rw-r--r--libs/hwui/RenderNode.cpp4
-rw-r--r--libs/hwui/RenderNode.h2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp9
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp1
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp8
-rw-r--r--location/java/android/location/Address.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java15
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java32
-rw-r--r--packages/SystemUI/res/layout/qs_paged_page.xml2
-rw-r--r--packages/SystemUI/res/layout/qs_paged_tile_layout.xml1
-rw-r--r--packages/SystemUI/res/values-h320dp/config.xml22
-rw-r--r--packages/SystemUI/res/values-h600dp/config.xml22
-rw-r--r--packages/SystemUI/res/values/config.xml18
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java135
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java220
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java262
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java78
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java30
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java14
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java300
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java45
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java41
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerService.java228
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java2
-rw-r--r--services/core/java/com/android/server/am/CompatModePackages.java20
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java43
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java68
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java105
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java14
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java116
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java13
-rw-r--r--services/core/java/com/android/server/security/VerityUtils.java6
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java8
-rw-r--r--services/core/java/com/android/server/wm/Session.java25
-rw-r--r--services/core/java/com/android/server/wm/WindowFrames.java36
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java28
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java118
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java72
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java61
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java345
-rw-r--r--telephony/java/android/telephony/SmsMessage.java2
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java34
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java34
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl11
-rw-r--r--telephony/java/com/android/internal/telephony/OperatorInfo.java2
-rw-r--r--tests/ImfTest/Android.mk16
-rw-r--r--tests/ImfTest/AndroidManifest.xml146
-rw-r--r--tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml36
-rw-r--r--tests/ImfTest/res/layout/full_screen_edit_text.xml27
-rw-r--r--tests/ImfTest/res/layout/one_edit_text_activity.xml50
-rw-r--r--tests/ImfTest/res/layout/sample_edit_text.xml53
-rw-r--r--tests/ImfTest/res/values/config.xml21
-rw-r--r--tests/ImfTest/res/values/strings.xml50
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java100
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java95
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java63
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java63
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java72
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java72
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java62
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java62
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java78
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java114
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java111
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java156
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java66
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java68
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java61
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java72
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java71
-rw-r--r--tests/ImfTest/tests/Android.mk18
-rw-r--r--tests/ImfTest/tests/AndroidManifest.xml36
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java49
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java48
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java48
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java49
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java49
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java49
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java58
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java149
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java40
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java36
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java37
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java37
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java50
-rw-r--r--tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java53
-rw-r--r--tools/aapt2/development.md11
179 files changed, 3197 insertions, 4412 deletions
diff --git a/api/current.txt b/api/current.txt
index 6042b2fa4c32..3beb491c5412 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -42787,6 +42787,7 @@ package android.telephony {
method public static int getDefaultSubscriptionId();
method public static int getDefaultVoiceSubscriptionId();
method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
+ method public static int getSlotIndex(int);
method public static int[] getSubscriptionIds(int);
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
method public boolean isNetworkRoaming(int);
@@ -42804,7 +42805,9 @@ package android.telephony {
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+ field public static final int INVALID_SIM_SLOT_INDEX = -2; // 0xfffffffe
field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
+ field public static final int SIM_NOT_INSERTED = -3; // 0xfffffffd
}
public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index e14f2eb41816..d334f96d47fb 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -198,8 +198,7 @@ int main(int argc, char** argv)
sp<GraphicBuffer> outBuffer;
status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */,
- 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation,
- &outBuffer);
+ 0 /* reqHeight */, false, captureOrientation, &outBuffer);
if (result != NO_ERROR) {
close(fd);
return 1;
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 5e87ef658dd5..27c5a1701c0d 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -67,7 +67,9 @@ statsd_common_src := \
src/subscriber/SubscriberReporter.cpp \
src/HashableDimensionKey.cpp \
src/guardrail/StatsdStats.cpp \
- src/socket/StatsSocketListener.cpp
+ src/socket/StatsSocketListener.cpp \
+ src/shell/ShellSubscriber.cpp \
+ src/shell/shell_config.proto
# TODO(b/110563449): Once statsd is using a blueprint file, migrate to the proper filegroups.
statsd_common_src += \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 8e02f9cb7628..f4c70bee2806 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -257,12 +257,18 @@ size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) const {
return it->second->byteSize();
}
-void StatsLogProcessor::dumpStates(FILE* out, bool verbose) {
+void StatsLogProcessor::dumpStates(int out, bool verbose) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- fprintf(out, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size());
+ FILE* fout = fdopen(out, "w");
+ if (fout == NULL) {
+ return;
+ }
+ fprintf(fout, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size());
for (auto metricsManager : mMetricsManagers) {
- metricsManager.second->dumpStates(out, verbose);
+ metricsManager.second->dumpStates(fout, verbose);
}
+
+ fclose(fout);
}
/*
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index df80b8e6e052..4091d951ba06 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -83,7 +83,7 @@ public:
return mUidMap;
}
- void dumpStates(FILE* out, bool verbose);
+ void dumpStates(int outFd, bool verbose);
void informPullAlarmFired(const int64_t timestampNs);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 9a7934576abd..2ef1169851ff 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -34,13 +34,14 @@
#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
-#include <utils/Looper.h>
-#include <utils/String16.h>
#include <statslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
#include <unistd.h>
+#include <utils/Looper.h>
+#include <utils/String16.h>
+#include <chrono>
using namespace android;
@@ -214,30 +215,8 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
sp<IResultReceiver> resultReceiver =
IResultReceiver::asInterface(data.readStrongBinder());
- FILE* fin = fdopen(in, "r");
- FILE* fout = fdopen(out, "w");
- FILE* ferr = fdopen(err, "w");
-
- if (fin == NULL || fout == NULL || ferr == NULL) {
- resultReceiver->send(NO_MEMORY);
- } else {
- err = command(fin, fout, ferr, args);
- resultReceiver->send(err);
- }
-
- if (fin != NULL) {
- fflush(fin);
- fclose(fin);
- }
- if (fout != NULL) {
- fflush(fout);
- fclose(fout);
- }
- if (fout != NULL) {
- fflush(ferr);
- fclose(ferr);
- }
-
+ err = command(in, out, err, args, resultReceiver);
+ resultReceiver->send(err);
return NO_ERROR;
}
default: { return BnStatsManager::onTransact(code, data, reply, flags); }
@@ -251,10 +230,6 @@ status_t StatsService::dump(int fd, const Vector<String16>& args) {
if (!checkCallingPermission(String16(kPermissionDump))) {
return PERMISSION_DENIED;
}
- FILE* out = fdopen(fd, "w");
- if (out == NULL) {
- return NO_MEMORY; // the fd is already open
- }
bool verbose = false;
bool proto = false;
@@ -265,21 +240,20 @@ status_t StatsService::dump(int fd, const Vector<String16>& args) {
proto = true;
}
- dump_impl(out, verbose, proto);
+ dump_impl(fd, verbose, proto);
- fclose(out);
return NO_ERROR;
}
/**
* Write debugging data about statsd in text or proto format.
*/
-void StatsService::dump_impl(FILE* out, bool verbose, bool proto) {
+void StatsService::dump_impl(int out, bool verbose, bool proto) {
if (proto) {
vector<uint8_t> data;
StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
for (size_t i = 0; i < data.size(); i ++) {
- fprintf(out, "%c", data[i]);
+ dprintf(out, "%c", data[i]);
}
} else {
StatsdStats::getInstance().dumpStats(out);
@@ -290,7 +264,8 @@ void StatsService::dump_impl(FILE* out, bool verbose, bool proto) {
/**
* Implementation of the adb shell cmd stats command.
*/
-status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
+ sp<IResultReceiver> resultReceiver) {
uid_t uid = IPCThreadState::self()->getCallingUid();
if (uid != AID_ROOT && uid != AID_SHELL) {
return PERMISSION_DENIED;
@@ -342,97 +317,106 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
if (!args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, args);
}
+ if (!args[0].compare(String8("data-subscribe"))) {
+ if (mShellSubscriber == nullptr) {
+ mShellSubscriber = new ShellSubscriber(mUidMap);
+ }
+ mShellSubscriber->startNewSubscription(in, out, resultReceiver);
+ return NO_ERROR;
+ }
}
print_cmd_help(out);
return NO_ERROR;
}
-void StatsService::print_cmd_help(FILE* out) {
- fprintf(out,
+void StatsService::print_cmd_help(int out) {
+ dprintf(out,
"usage: adb shell cmd stats print-stats-log [tag_required] "
"[timestamp_nsec_optional]\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats meminfo\n");
- fprintf(out, "\n");
- fprintf(out, " Prints the malloc debug information. You need to run the following first: \n");
- fprintf(out, " # adb shell stop\n");
- fprintf(out, " # adb shell setprop libc.debug.malloc.program statsd \n");
- fprintf(out, " # adb shell setprop libc.debug.malloc.options backtrace \n");
- fprintf(out, " # adb shell start\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats print-uid-map [PKG]\n");
- fprintf(out, "\n");
- fprintf(out, " Prints the UID, app name, version mapping.\n");
- fprintf(out, " PKG Optional package name to print the uids of the package\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
- fprintf(out, "\n");
- fprintf(out, " Prints the output of a pulled metrics source (int indicates source)\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats write-to-disk \n");
- fprintf(out, "\n");
- fprintf(out, " Flushes all data on memory to disk.\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
- fprintf(out, " Writes an AppBreadcrumbReported event to the statslog buffer.\n");
- fprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
- fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
- fprintf(out, " uid is used.\n");
- fprintf(out, " LABEL Integer in [0, 15], as per atoms.proto.\n");
- fprintf(out, " STATE Integer in [0, 3], as per atoms.proto.\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
- fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
- fprintf(out, "\n");
- fprintf(out, " Adds, updates or removes a configuration. The proto should be in\n");
- fprintf(out, " wire-encoded protobuf format and passed via stdin. If no UID and name is\n");
- fprintf(out, " provided, then all configs will be removed from memory and disk.\n");
- fprintf(out, "\n");
- fprintf(out, " UID The uid to use. It is only possible to pass the UID\n");
- fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
- fprintf(out, " uid is used.\n");
- fprintf(out, " NAME The per-uid name to use\n");
- fprintf(out, "\n");
- fprintf(out, "\n *Note: If both UID and NAME are omitted then all configs will\n");
- fprintf(out, "\n be removed from memory and disk!\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME [--include_current_bucket] [--proto]\n");
- fprintf(out, " Dump all metric data for a configuration.\n");
- fprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
- fprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
- fprintf(out, " calling uid is used.\n");
- fprintf(out, " NAME The name of the configuration\n");
- fprintf(out, " --proto Print proto binary.\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
- fprintf(out, " Send a broadcast that triggers the subscriber to fetch metrics.\n");
- fprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
- fprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
- fprintf(out, " calling uid is used.\n");
- fprintf(out, " NAME The name of the configuration\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats print-stats\n");
- fprintf(out, " Prints some basic stats.\n");
- fprintf(out, " --proto Print proto binary instead of string format.\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
- fprintf(out, " Clear cached puller data.\n");
- fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats print-logs\n");
- fprintf(out, " Only works on eng build\n");
-}
-
-status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats meminfo\n");
+ dprintf(out, "\n");
+ dprintf(out, " Prints the malloc debug information. You need to run the following first: \n");
+ dprintf(out, " # adb shell stop\n");
+ dprintf(out, " # adb shell setprop libc.debug.malloc.program statsd \n");
+ dprintf(out, " # adb shell setprop libc.debug.malloc.options backtrace \n");
+ dprintf(out, " # adb shell start\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats print-uid-map [PKG]\n");
+ dprintf(out, "\n");
+ dprintf(out, " Prints the UID, app name, version mapping.\n");
+ dprintf(out, " PKG Optional package name to print the uids of the package\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
+ dprintf(out, "\n");
+ dprintf(out, " Prints the output of a pulled metrics source (int indicates source)\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats write-to-disk \n");
+ dprintf(out, "\n");
+ dprintf(out, " Flushes all data on memory to disk.\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
+ dprintf(out, " Writes an AppBreadcrumbReported event to the statslog buffer.\n");
+ dprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
+ dprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
+ dprintf(out, " uid is used.\n");
+ dprintf(out, " LABEL Integer in [0, 15], as per atoms.proto.\n");
+ dprintf(out, " STATE Integer in [0, 3], as per atoms.proto.\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
+ dprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
+ dprintf(out, "\n");
+ dprintf(out, " Adds, updates or removes a configuration. The proto should be in\n");
+ dprintf(out, " wire-encoded protobuf format and passed via stdin. If no UID and name is\n");
+ dprintf(out, " provided, then all configs will be removed from memory and disk.\n");
+ dprintf(out, "\n");
+ dprintf(out, " UID The uid to use. It is only possible to pass the UID\n");
+ dprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
+ dprintf(out, " uid is used.\n");
+ dprintf(out, " NAME The per-uid name to use\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n *Note: If both UID and NAME are omitted then all configs will\n");
+ dprintf(out, "\n be removed from memory and disk!\n");
+ dprintf(out, "\n");
+ dprintf(out,
+ "usage: adb shell cmd stats dump-report [UID] NAME [--include_current_bucket] "
+ "[--proto]\n");
+ dprintf(out, " Dump all metric data for a configuration.\n");
+ dprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
+ dprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
+ dprintf(out, " calling uid is used.\n");
+ dprintf(out, " NAME The name of the configuration\n");
+ dprintf(out, " --proto Print proto binary.\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
+ dprintf(out, " Send a broadcast that triggers the subscriber to fetch metrics.\n");
+ dprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
+ dprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
+ dprintf(out, " calling uid is used.\n");
+ dprintf(out, " NAME The name of the configuration\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats print-stats\n");
+ dprintf(out, " Prints some basic stats.\n");
+ dprintf(out, " --proto Print proto binary instead of string format.\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
+ dprintf(out, " Clear cached puller data.\n");
+ dprintf(out, "\n");
+ dprintf(out, "usage: adb shell cmd stats print-logs\n");
+ dprintf(out, " Only works on eng build\n");
+}
+
+status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
string name;
bool good = false;
int uid;
@@ -456,9 +440,9 @@ status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
}
}
} else {
- fprintf(out,
+ dprintf(out,
"The metrics can only be dumped for other UIDs on eng or userdebug "
- "builds.\n");
+ "builds.\n");
}
}
if (!good) {
@@ -481,7 +465,7 @@ status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
return NO_ERROR;
}
-status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
const int argCount = args.size();
if (argCount >= 2) {
if (args[1] == "update" || args[1] == "remove") {
@@ -508,7 +492,7 @@ status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8
}
}
} else {
- fprintf(err,
+ dprintf(err,
"The config can only be set for other UIDs on eng or userdebug "
"builds.\n");
}
@@ -526,21 +510,21 @@ status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8
char* endp;
int64_t configID = strtoll(name.c_str(), &endp, 10);
if (endp == name.c_str() || *endp != '\0') {
- fprintf(err, "Error parsing config ID.\n");
+ dprintf(err, "Error parsing config ID.\n");
return UNKNOWN_ERROR;
}
// Read stream into buffer.
string buffer;
- if (!android::base::ReadFdToString(fileno(in), &buffer)) {
- fprintf(err, "Error reading stream for StatsConfig.\n");
+ if (!android::base::ReadFdToString(in, &buffer)) {
+ dprintf(err, "Error reading stream for StatsConfig.\n");
return UNKNOWN_ERROR;
}
// Parse buffer.
StatsdConfig config;
if (!config.ParseFromString(buffer)) {
- fprintf(err, "Error parsing proto stream for StatsConfig.\n");
+ dprintf(err, "Error parsing proto stream for StatsConfig.\n");
return UNKNOWN_ERROR;
}
@@ -562,7 +546,7 @@ status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8
return UNKNOWN_ERROR;
}
-status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args) {
+status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) {
if (mProcessor != nullptr) {
int argCount = args.size();
bool good = false;
@@ -597,7 +581,7 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
}
}
} else {
- fprintf(out,
+ dprintf(out,
"The metrics can only be dumped for other UIDs on eng or userdebug "
"builds.\n");
}
@@ -608,11 +592,11 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
includeCurrentBucket, ADB_DUMP, &data);
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
- fprintf(out, "%c", data[i]);
+ dprintf(out, "%c", data[i]);
}
} else {
- fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
- fprintf(out, "See the StatsLogReport in logcat...\n");
+ dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
+ dprintf(out, "See the StatsLogReport in logcat...\n");
}
return android::OK;
} else {
@@ -621,12 +605,12 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
return UNKNOWN_ERROR;
}
} else {
- fprintf(out, "Log processor does not exist...\n");
+ dprintf(out, "Log processor does not exist...\n");
return UNKNOWN_ERROR;
}
}
-status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_stats(int out, const Vector<String8>& args) {
int argCount = args.size();
bool proto = false;
if (!std::strcmp("--proto", args[argCount-1].c_str())) {
@@ -638,13 +622,13 @@ status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) {
vector<uint8_t> data;
statsdStats.dumpStats(&data, false); // does not reset statsdStats.
for (size_t i = 0; i < data.size(); i ++) {
- fprintf(out, "%c", data[i]);
+ dprintf(out, "%c", data[i]);
}
} else {
vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
for (const ConfigKey& key : configs) {
- fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
+ dprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
mProcessor->GetMetricsSize(key));
}
statsdStats.dumpStats(out);
@@ -652,29 +636,29 @@ status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) {
return NO_ERROR;
}
-status_t StatsService::cmd_print_uid_map(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_uid_map(int out, const Vector<String8>& args) {
if (args.size() > 1) {
string pkg;
pkg.assign(args[1].c_str(), args[1].size());
auto uids = mUidMap->getAppUid(pkg);
- fprintf(out, "%s -> [ ", pkg.c_str());
+ dprintf(out, "%s -> [ ", pkg.c_str());
for (const auto& uid : uids) {
- fprintf(out, "%d ", uid);
+ dprintf(out, "%d ", uid);
}
- fprintf(out, "]\n");
+ dprintf(out, "]\n");
} else {
mUidMap->printUidMap(out);
}
return NO_ERROR;
}
-status_t StatsService::cmd_write_data_to_disk(FILE* out) {
- fprintf(out, "Writing data to disk\n");
+status_t StatsService::cmd_write_data_to_disk(int out) {
+ dprintf(out, "Writing data to disk\n");
mProcessor->WriteDataToDisk(ADB_DUMP);
return NO_ERROR;
}
-status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_log_app_breadcrumb(int out, const Vector<String8>& args) {
bool good = false;
int32_t uid;
int32_t label;
@@ -695,13 +679,13 @@ status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>&
state = atoi(args[3].c_str());
good = true;
} else {
- fprintf(out,
+ dprintf(out,
"Selecting a UID for writing AppBreadcrumb can only be done for other UIDs "
- "on eng or userdebug builds.\n");
+ "on eng or userdebug builds.\n");
}
}
if (good) {
- fprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
+ dprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
} else {
print_cmd_help(out);
@@ -710,46 +694,46 @@ status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>&
return NO_ERROR;
}
-status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_pulled_metrics(int out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
vector<shared_ptr<LogEvent> > stats;
if (mPullerManager->Pull(s, getElapsedRealtimeNs(), &stats)) {
for (const auto& it : stats) {
- fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ dprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
}
- fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+ dprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
return NO_ERROR;
}
return UNKNOWN_ERROR;
}
-status_t StatsService::cmd_remove_all_configs(FILE* out) {
- fprintf(out, "Removing all configs...\n");
+status_t StatsService::cmd_remove_all_configs(int out) {
+ dprintf(out, "Removing all configs...\n");
VLOG("StatsService::cmd_remove_all_configs was called");
mConfigManager->RemoveAllConfigs();
StorageManager::deleteAllFiles(STATS_SERVICE_DIR);
return NO_ERROR;
}
-status_t StatsService::cmd_dump_memory_info(FILE* out) {
- fprintf(out, "meminfo not available.\n");
+status_t StatsService::cmd_dump_memory_info(int out) {
+ dprintf(out, "meminfo not available.\n");
return NO_ERROR;
}
-status_t StatsService::cmd_clear_puller_cache(FILE* out) {
+status_t StatsService::cmd_clear_puller_cache(int out) {
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
int cleared = mPullerManager->ForceClearPullerCache();
- fprintf(out, "Puller removed %d cached data!\n", cleared);
+ dprintf(out, "Puller removed %d cached data!\n", cleared);
return NO_ERROR;
} else {
return PERMISSION_DENIED;
}
}
-status_t StatsService::cmd_print_logs(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", ipc->getCallingPid(),
ipc->getCallingUid());
@@ -885,6 +869,9 @@ void StatsService::Startup() {
void StatsService::OnLogEvent(LogEvent* event) {
mProcessor->OnLogEvent(event);
+ if (mShellSubscriber != nullptr) {
+ mShellSubscriber->onLogEvent(*event);
+ }
}
Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 613f509e915a..06189278abce 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -24,6 +24,7 @@
#include "external/StatsPullerManager.h"
#include "logd/LogListener.h"
#include "packages/UidMap.h"
+#include "shell/ShellSubscriber.h"
#include "statscompanion_util.h"
#include <android/os/BnStatsManager.h>
@@ -54,7 +55,8 @@ public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
virtual status_t dump(int fd, const Vector<String16>& args);
- virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+ virtual status_t command(int inFd, int outFd, int err, Vector<String8>& args,
+ sp<IResultReceiver> resultReceiver);
virtual Status systemRunning();
virtual Status statsCompanionReady();
@@ -162,73 +164,73 @@ private:
/**
* Text or proto output of dumpsys.
*/
- void dump_impl(FILE* out, bool verbose, bool proto);
+ void dump_impl(int outFd, bool verbose, bool proto);
/**
* Print usage information for the commands
*/
- void print_cmd_help(FILE* out);
+ void print_cmd_help(int out);
/**
* Trigger a broadcast.
*/
- status_t cmd_trigger_broadcast(FILE* out, Vector<String8>& args);
+ status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);
/**
* Handle the config sub-command.
*/
- status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+ status_t cmd_config(int inFd, int outFd, int err, Vector<String8>& args);
/**
* Prints some basic stats to std out.
*/
- status_t cmd_print_stats(FILE* out, const Vector<String8>& args);
+ status_t cmd_print_stats(int outFd, const Vector<String8>& args);
/**
* Print the event log.
*/
- status_t cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args);
+ status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args);
/**
* Print the mapping of uids to package names.
*/
- status_t cmd_print_uid_map(FILE* out, const Vector<String8>& args);
+ status_t cmd_print_uid_map(int outFd, const Vector<String8>& args);
/**
* Flush the data to disk.
*/
- status_t cmd_write_data_to_disk(FILE* out);
+ status_t cmd_write_data_to_disk(int outFd);
/**
* Write an AppBreadcrumbReported event to the StatsLog buffer, as if calling
* StatsLog.write(APP_BREADCRUMB_REPORTED).
*/
- status_t cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args);
+ status_t cmd_log_app_breadcrumb(int outFd, const Vector<String8>& args);
/**
* Print contents of a pulled metrics source.
*/
- status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
+ status_t cmd_print_pulled_metrics(int outFd, const Vector<String8>& args);
/**
* Removes all configs stored on disk and on memory.
*/
- status_t cmd_remove_all_configs(FILE* out);
+ status_t cmd_remove_all_configs(int outFd);
/*
* Dump memory usage by statsd.
*/
- status_t cmd_dump_memory_info(FILE* out);
+ status_t cmd_dump_memory_info(int outFd);
/*
* Clear all puller cached data
*/
- status_t cmd_clear_puller_cache(FILE* out);
+ status_t cmd_clear_puller_cache(int outFd);
/**
* Print all stats logs received to logcat.
*/
- status_t cmd_print_logs(FILE* out, const Vector<String8>& args);
+ status_t cmd_print_logs(int outFd, const Vector<String8>& args);
/**
* Adds a configuration after checking permissions and obtaining UID from binder call.
@@ -275,6 +277,8 @@ private:
*/
bool mEngBuild;
+ sp<ShellSubscriber> mShellSubscriber;
+
FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b8f19ee0d558..c6c10ec7e3d9 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2339,7 +2339,7 @@ message BinderCallsExceptions {
* Next tag: 11
*/
message LooperStats {
- // Currently not collected and always set to 0.
+ // The uid that made a call to the System Server and caused the message to be enqueued.
optional int32 uid = 1 [(is_uid) = true];
// Fully qualified class name of the handler target class.
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 33f3917f05ad..bf0bfec9c08d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -400,36 +400,35 @@ string buildTimeString(int64_t timeSec) {
return string(timeBuffer);
}
-void StatsdStats::dumpStats(FILE* out) const {
+void StatsdStats::dumpStats(int out) const {
lock_guard<std::mutex> lock(mLock);
time_t t = mStartTimeSec;
struct tm* tm = localtime(&t);
char timeBuffer[80];
strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm);
- fprintf(out, "Stats collection start second: %s\n", timeBuffer);
- fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
+ dprintf(out, "Stats collection start second: %s\n", timeBuffer);
+ dprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
for (const auto& configStats : mIceBox) {
- fprintf(out,
+ dprintf(out,
"Config {%d_%lld}: creation=%d, deletion=%d, reset=%d, #metric=%d, #condition=%d, "
"#matcher=%d, #alert=%d, valid=%d\n",
configStats->uid, (long long)configStats->id, configStats->creation_time_sec,
configStats->deletion_time_sec, configStats->reset_time_sec,
- configStats->metric_count,
- configStats->condition_count, configStats->matcher_count, configStats->alert_count,
- configStats->is_valid);
+ configStats->metric_count, configStats->condition_count, configStats->matcher_count,
+ configStats->alert_count, configStats->is_valid);
for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
- fprintf(out, "\tbroadcast time: %d\n", broadcastTime);
+ dprintf(out, "\tbroadcast time: %d\n", broadcastTime);
}
for (const auto& dataDropTime : configStats->data_drop_time_sec) {
- fprintf(out, "\tdata drop time: %d\n", dataDropTime);
+ dprintf(out, "\tdata drop time: %d\n", dataDropTime);
}
}
- fprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size());
+ dprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size());
for (auto& pair : mConfigStats) {
auto& configStats = pair.second;
- fprintf(out,
+ dprintf(out,
"Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
"#matcher=%d, #alert=%d, valid=%d\n",
configStats->uid, (long long)configStats->id, configStats->creation_time_sec,
@@ -437,81 +436,81 @@ void StatsdStats::dumpStats(FILE* out) const {
configStats->condition_count, configStats->matcher_count, configStats->alert_count,
configStats->is_valid);
for (const auto& annotation : configStats->annotations) {
- fprintf(out, "\tannotation: %lld, %d\n", (long long)annotation.first,
+ dprintf(out, "\tannotation: %lld, %d\n", (long long)annotation.first,
annotation.second);
}
for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
- fprintf(out, "\tbroadcast time: %s(%lld)\n",
- buildTimeString(broadcastTime).c_str(), (long long)broadcastTime);
+ dprintf(out, "\tbroadcast time: %s(%lld)\n", buildTimeString(broadcastTime).c_str(),
+ (long long)broadcastTime);
}
for (const auto& dataDropTime : configStats->data_drop_time_sec) {
- fprintf(out, "\tdata drop time: %s(%lld)\n",
- buildTimeString(dataDropTime).c_str(), (long long)dataDropTime);
+ dprintf(out, "\tdata drop time: %s(%lld)\n", buildTimeString(dataDropTime).c_str(),
+ (long long)dataDropTime);
}
for (const auto& dump : configStats->dump_report_stats) {
- fprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
+ dprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
buildTimeString(dump.first).c_str(), (long long)dump.first,
(long long)dump.second);
}
for (const auto& stats : pair.second->matcher_stats) {
- fprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, stats.second);
+ dprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, stats.second);
}
for (const auto& stats : pair.second->condition_stats) {
- fprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first,
+ dprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first,
stats.second);
}
for (const auto& stats : pair.second->condition_stats) {
- fprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first,
+ dprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first,
stats.second);
}
for (const auto& stats : pair.second->alert_stats) {
- fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
+ dprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
}
}
- fprintf(out, "********Disk Usage stats***********\n");
+ dprintf(out, "********Disk Usage stats***********\n");
StorageManager::printStats(out);
- fprintf(out, "********Pushed Atom stats***********\n");
+ dprintf(out, "********Pushed Atom stats***********\n");
const size_t atomCounts = mPushedAtomStats.size();
for (size_t i = 2; i < atomCounts; i++) {
if (mPushedAtomStats[i] > 0) {
- fprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
+ dprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
}
}
- fprintf(out, "********Pulled Atom stats***********\n");
+ dprintf(out, "********Pulled Atom stats***********\n");
for (const auto& pair : mPulledAtomStats) {
- fprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull,
+ dprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull,
(long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec);
}
if (mAnomalyAlarmRegisteredStats > 0) {
- fprintf(out, "********AnomalyAlarmStats stats***********\n");
- fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
+ dprintf(out, "********AnomalyAlarmStats stats***********\n");
+ dprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
}
if (mPeriodicAlarmRegisteredStats > 0) {
- fprintf(out, "********SubscriberAlarmStats stats***********\n");
- fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
+ dprintf(out, "********SubscriberAlarmStats stats***********\n");
+ dprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
}
- fprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
+ dprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
mUidMapStats.bytes_used, mUidMapStats.changes, mUidMapStats.deleted_apps,
mUidMapStats.dropped_changes);
for (const auto& restart : mSystemServerRestartSec) {
- fprintf(out, "System server restarts at %s(%lld)\n",
- buildTimeString(restart).c_str(), (long long)restart);
+ dprintf(out, "System server restarts at %s(%lld)\n", buildTimeString(restart).c_str(),
+ (long long)restart);
}
for (const auto& loss : mLogLossStats) {
- fprintf(out, "Log loss: %lld (wall clock sec) - %d (count)\n", (long long)loss.first,
+ dprintf(out, "Log loss: %lld (wall clock sec) - %d (count)\n", (long long)loss.first,
loss.second);
}
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index b5156dadade6..a8188c89928a 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -156,7 +156,7 @@ public:
* Report a config has been removed.
*/
void noteConfigRemoved(const ConfigKey& key);
- /**
+ /**
* Report a config has been reset when ttl expires.
*/
void noteConfigReset(const ConfigKey& key);
@@ -202,7 +202,6 @@ public:
*/
void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
-
/**
* Report the max size of output tuple of dimension in condition across dimensions in what.
*
@@ -272,8 +271,8 @@ public:
void notePullFromCache(int pullAtomId);
/*
- * Records when system server restarts.
- */
+ * Records when system server restarts.
+ */
void noteSystemServerRestart(int32_t timeSec);
/**
@@ -296,9 +295,9 @@ public:
void dumpStats(std::vector<uint8_t>* buffer, bool reset);
/**
- * Output statsd stats in human readable format to [out] file.
+ * Output statsd stats in human readable format to [out] file descriptor.
*/
- void dumpStats(FILE* out) const;
+ void dumpStats(int outFd) const;
typedef struct {
long totalPull;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index be94725991af..4325f0fd77bd 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -386,12 +386,12 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
StatsdStats::getInstance().setUidMapChanges(mChanges.size());
}
-void UidMap::printUidMap(FILE* out) const {
+void UidMap::printUidMap(int out) const {
lock_guard<mutex> lock(mMutex);
for (const auto& kv : mMap) {
if (!kv.second.deleted) {
- fprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode,
+ dprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode,
kv.first.first);
}
}
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 91f203084388..4598369f1222 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -103,7 +103,7 @@ public:
// Helper for debugging contents of this uid map. Can be triggered with:
// adb shell cmd stats print-uid-map
- void printUidMap(FILE* out) const;
+ void printUidMap(int outFd) const;
// Commands for indicating to the map that a producer should be notified if an app is updated.
// This allows the metric producer to distinguish when the same uid or app represents a
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
new file mode 100644
index 000000000000..3cd49d722fea
--- /dev/null
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "ShellSubscriber.h"
+
+#include "matchers/matcher_util.h"
+
+#include <android-base/file.h>
+
+using android::util::ProtoOutputStream;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver) {
+ VLOG("start new shell subscription");
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mResultReceiver != nullptr) {
+ VLOG("Only one shell subscriber is allowed.");
+ return;
+ }
+ mInput = in;
+ mOutput = out;
+ mResultReceiver = resultReceiver;
+ IInterface::asBinder(mResultReceiver)->linkToDeath(this);
+ }
+
+ // Spawn another thread to read the config updates from the input file descriptor
+ std::thread reader([in, this] { readConfig(in); });
+ reader.detach();
+
+ std::unique_lock<std::mutex> lk(mMutex);
+
+ mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+ if (reader.joinable()) {
+ reader.join();
+ }
+}
+
+void ShellSubscriber::updateConfig(const ShellSubscription& config) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPushedMatchers.clear();
+ for (const auto& pushed : config.pushed()) {
+ mPushedMatchers.push_back(pushed);
+ VLOG("adding matcher for atom %d", pushed.atom_id());
+ }
+}
+
+void ShellSubscriber::readConfig(int in) {
+ if (in <= 0) {
+ return;
+ }
+
+ while (1) {
+ size_t bufferSize = 0;
+ int result = 0;
+ if ((result = read(in, &bufferSize, sizeof(bufferSize))) == 0) {
+ VLOG("Done reading");
+ break;
+ } else if (result < 0 || result != sizeof(bufferSize)) {
+ ALOGE("Error reading config size");
+ break;
+ }
+
+ vector<uint8_t> buffer(bufferSize);
+ if ((result = read(in, buffer.data(), bufferSize)) > 0 && ((size_t)result) == bufferSize) {
+ ShellSubscription config;
+ if (config.ParseFromArray(buffer.data(), bufferSize)) {
+ updateConfig(config);
+ } else {
+ ALOGE("error parsing the config");
+ break;
+ }
+ } else {
+ VLOG("Error reading the config, returned: %d, expecting %zu", result, bufferSize);
+ break;
+ }
+ }
+}
+
+void ShellSubscriber::cleanUpLocked() {
+ // The file descriptors will be closed by binder.
+ mInput = 0;
+ mOutput = 0;
+ mResultReceiver = nullptr;
+ mPushedMatchers.clear();
+ VLOG("done clean up");
+}
+
+void ShellSubscriber::onLogEvent(const LogEvent& event) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mOutput <= 0) {
+ return;
+ }
+
+ for (const auto& matcher : mPushedMatchers) {
+ if (matchesSimple(*mUidMap, matcher, event)) {
+ // First write the payload size.
+ size_t bufferSize = mProto.size();
+ write(mOutput, &bufferSize, sizeof(bufferSize));
+
+ // Then write the payload.
+ event.ToProto(mProto);
+ mProto.flush(mOutput);
+ mProto.clear();
+ break;
+ }
+ }
+}
+
+void ShellSubscriber::binderDied(const wp<IBinder>& who) {
+ {
+ VLOG("Shell exits");
+ std::lock_guard<std::mutex> lock(mMutex);
+ cleanUpLocked();
+ }
+ mShellDied.notify_all();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
new file mode 100644
index 000000000000..0ace35fab850
--- /dev/null
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "logd/LogEvent.h"
+
+#include <android/util/ProtoOutputStream.h>
+#include <binder/IResultReceiver.h>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "packages/UidMap.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Handles atoms subscription via shell cmd.
+ *
+ * A shell subscription lasts *until shell exits*. Unlike config based clients, a shell client
+ * communicates with statsd via file descriptors. They can subscribe pushed and pulled atoms.
+ * The atoms are sent back to the client in real time, as opposed to
+ * keeping the data in memory. Shell clients do not subscribe aggregated metrics, as they are
+ * responsible for doing the aggregation after receiving the atom events.
+ *
+ * Shell client pass ShellSubscription in the proto binary format. Client can update the
+ * subscription by sending a new subscription. The new subscription would replace the old one.
+ * Input data stream format is:
+ *
+ * |size_t|subscription proto|size_t|subscription proto|....
+ *
+ * statsd sends the events back in Atom proto binary format. Each Atom message is preceded
+ * with sizeof(size_t) bytes indicating the size of the proto message payload.
+ *
+ * The stream would be in the following format:
+ * |size_t|atom1 proto|size_t|atom2 proto|....
+ *
+ * Only one shell subscriber allowed at a time, because each shell subscriber blocks one thread
+ * until it exits.
+ */
+class ShellSubscriber : public virtual IBinder::DeathRecipient {
+public:
+ ShellSubscriber(sp<UidMap> uidMap) : mUidMap(uidMap){};
+
+ /**
+ * Start a new subscription.
+ */
+ void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver);
+
+ void binderDied(const wp<IBinder>& who);
+
+ void onLogEvent(const LogEvent& event);
+
+private:
+ void readConfig(int in);
+
+ void updateConfig(const ShellSubscription& config);
+
+ void cleanUpLocked();
+
+ sp<UidMap> mUidMap;
+
+ // bool mWritten = false;
+
+ android::util::ProtoOutputStream mProto;
+
+ mutable std::mutex mMutex;
+
+ std::condition_variable mShellDied; // semaphore for waiting until shell exits.
+
+ int mInput; // The input file descriptor
+
+ int mOutput; // The output file descriptor
+
+ sp<IResultReceiver> mResultReceiver;
+
+ std::vector<SimpleAtomMatcher> mPushedMatchers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/shell/shell_config.proto b/cmds/statsd/src/shell/shell_config.proto
new file mode 100644
index 000000000000..516693d4e7f7
--- /dev/null
+++ b/cmds/statsd/src/shell/shell_config.proto
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd;
+
+option java_package = "com.android.os";
+option java_outer_classname = "ShellConfig";
+
+import "frameworks/base/cmds/statsd/src/statsd_config.proto";
+
+message PulledAtomSubscription {
+ optional int32 atom_id = 1;
+
+ /* gap between two pulls in milliseconds */
+ optional int32 freq_millis = 2;
+}
+
+message ShellSubscription {
+ repeated SimpleAtomMatcher pushed = 1;
+ repeated PulledAtomSubscription pulled = 2;
+} \ No newline at end of file
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 3ebc8a492d68..2f19a02ecafe 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -392,13 +392,13 @@ void StorageManager::trimToFit(const char* path) {
}
}
-void StorageManager::printStats(FILE* out) {
- printDirStats(out, STATS_SERVICE_DIR);
- printDirStats(out, STATS_DATA_DIR);
+void StorageManager::printStats(int outFd) {
+ printDirStats(outFd, STATS_SERVICE_DIR);
+ printDirStats(outFd, STATS_DATA_DIR);
}
-void StorageManager::printDirStats(FILE* out, const char* path) {
- fprintf(out, "Printing stats of %s\n", path);
+void StorageManager::printDirStats(int outFd, const char* path) {
+ dprintf(outFd, "Printing stats of %s\n", path);
unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
if (dir == NULL) {
VLOG("Path %s does not exist", path);
@@ -418,25 +418,22 @@ void StorageManager::printDirStats(FILE* out, const char* path) {
int64_t timestamp = result[0];
int64_t uid = result[1];
int64_t configID = result[2];
- fprintf(out, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld",
- fileCount + 1,
- (long long)timestamp,
- (int)uid,
- (long long)configID);
+ dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld", fileCount + 1,
+ (long long)timestamp, (int)uid, (long long)configID);
string file_name = getFilePath(path, timestamp, uid, configID);
ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
if (file.is_open()) {
file.seekg(0, ios::end);
int fileSize = file.tellg();
file.close();
- fprintf(out, ", File Size: %d bytes", fileSize);
+ dprintf(outFd, ", File Size: %d bytes", fileSize);
totalFileSize += fileSize;
}
- fprintf(out, "\n");
+ dprintf(outFd, "\n");
fileCount++;
}
- fprintf(out, "\tTotal number of files: %d, Total size of files: %d bytes.\n",
- fileCount, totalFileSize);
+ dprintf(outFd, "\tTotal number of files: %d, Total size of files: %d bytes.\n", fileCount,
+ totalFileSize);
}
} // namespace statsd
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 4840f3c4fa34..8fbc89e4f657 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -100,13 +100,13 @@ public:
/**
* Prints disk usage statistics related to statsd.
*/
- static void printStats(FILE* out);
+ static void printStats(int out);
private:
/**
* Prints disk usage statistics about a directory related to statsd.
*/
- static void printDirStats(FILE* out, const char* path);
+ static void printDirStats(int out, const char* path);
};
} // namespace statsd
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e86a49d93cf9..055a91eaa1cc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -776,7 +776,7 @@ public class ActivityManager {
/** @hide */
public int getPackageScreenCompatMode(String packageName) {
try {
- return getService().getPackageScreenCompatMode(packageName);
+ return getTaskService().getPackageScreenCompatMode(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -785,7 +785,7 @@ public class ActivityManager {
/** @hide */
public void setPackageScreenCompatMode(String packageName, int mode) {
try {
- getService().setPackageScreenCompatMode(packageName, mode);
+ getTaskService().setPackageScreenCompatMode(packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -794,7 +794,7 @@ public class ActivityManager {
/** @hide */
public boolean getPackageAskScreenCompat(String packageName) {
try {
- return getService().getPackageAskScreenCompat(packageName);
+ return getTaskService().getPackageAskScreenCompat(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -803,7 +803,7 @@ public class ActivityManager {
/** @hide */
public void setPackageAskScreenCompat(String packageName, boolean ask) {
try {
- getService().setPackageAskScreenCompat(packageName, ask);
+ getTaskService().setPackageAskScreenCompat(packageName, ask);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 87366db56976..be1f2dbc8e4f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -18,6 +18,7 @@ package android.app;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -183,12 +184,6 @@ public abstract class ActivityManagerInternal {
/** Trims memory usage in the system by removing/stopping unused application processes. */
public abstract void trimApplications();
- /** Returns the screen compatibility mode for the given application. */
- public abstract int getPackageScreenCompatMode(ApplicationInfo ai);
-
- /** Sets the screen compatibility mode for the given application. */
- public abstract void setPackageScreenCompatMode(ApplicationInfo ai, int mode);
-
/** Closes all system dialogs. */
public abstract void closeSystemDialogs(String reason);
@@ -201,6 +196,11 @@ public abstract class ActivityManagerInternal {
public abstract boolean hasRunningActivity(int uid, @Nullable String packageName);
public abstract void updateOomAdj();
+ public abstract void updateCpuStats();
+ public abstract void updateUsageStats(
+ ComponentName activity, int uid, int userId, boolean resumed);
+ public abstract void updateForegroundTimeIfOnBattery(
+ String packageName, int uid, long cpuTimeDiff);
public abstract void sendForegroundProfileChanged(int userId);
/**
@@ -226,4 +226,10 @@ public abstract class ActivityManagerInternal {
/** Gets the task id for a given activity. */
public abstract int getTaskIdForActivity(@NonNull IBinder token, boolean onlyRoot);
+
+ public abstract void setBooting(boolean booting);
+ public abstract boolean isBooting();
+ public abstract void setBooted(boolean booted);
+ public abstract boolean isBooted();
+ public abstract void finishBooting();
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 37a05f0e1d3a..9d82ffa838ca 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -239,7 +239,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
* @param year the selected year
* @param month the selected month (0-11 for compatibility with
* {@link Calendar#MONTH})
- * @param dayOfMonth th selected day of the month (1-31, depending on
+ * @param dayOfMonth the selected day of the month (1-31, depending on
* month)
*/
void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 2490caef1b2f..c0c8b799ec3b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -248,10 +248,7 @@ interface IActivityManager {
boolean runGc, in String path, in ParcelFileDescriptor fd,
in RemoteCallback finishCallback);
boolean isUserRunning(int userid, int flags);
- int getPackageScreenCompatMode(in String packageName);
void setPackageScreenCompatMode(in String packageName, int mode);
- boolean getPackageAskScreenCompat(in String packageName);
- void setPackageAskScreenCompat(in String packageName, boolean ask);
boolean switchUser(int userid);
boolean removeTask(int taskId);
void registerProcessObserver(in IProcessObserver observer);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 46664c61fbb9..abd1cca06d26 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -422,4 +422,9 @@ interface IActivityTaskManager {
void resumeAppSwitches();
void setActivityController(in IActivityController watcher, boolean imAMonkey);
void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake);
+
+ int getPackageScreenCompatMode(in String packageName);
+ void setPackageScreenCompatMode(in String packageName, int mode);
+ boolean getPackageAskScreenCompat(in String packageName);
+ void setPackageAskScreenCompat(in String packageName, boolean ask);
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 4f172a4251d4..e532ecec95bc 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -25,7 +25,6 @@ import android.content.res.Configuration;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -214,7 +213,7 @@ public class UiModeManager {
}
/**
- * Sets the night mode.
+ * Sets the system-wide night mode.
* <p>
* The mode can be one of:
* <ul>
@@ -231,6 +230,12 @@ public class UiModeManager {
* are only effective when the {@link Configuration#UI_MODE_TYPE_CAR car}
* or {@link Configuration#UI_MODE_TYPE_DESK desk} mode is enabled on a
* device. Starting in API 23, changes to night mode are always effective.
+ * <p>
+ * Changes to night mode take effect globally and will result in a configuration change
+ * (and potentially an Activity lifecycle event) being applied to all running apps.
+ * Developers interested in an app-local implementation of night mode should consider using
+ * {@link androidx.appcompat.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the
+ * -night qualifier locally.
*
* @param mode the night mode to set
* @see #getNightMode()
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bd7a2ddb5af8..fc67c10e7e5e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3450,15 +3450,14 @@ public class DevicePolicyManager {
* @param flags Bit mask of additional options: currently supported flags are
* {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
* @param reason a string that contains the reason for wiping data, which can be
- * presented to the user.
+ * presented to the user. If the string is null or empty, user won't be notified.
* @throws SecurityException if the calling application does not own an active administrator
* that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
* @throws IllegalArgumentException if the input reason string is null or empty.
*/
- public void wipeData(int flags, @NonNull CharSequence reason) {
+ public void wipeData(int flags, CharSequence reason) {
throwIfParentInstance("wipeData");
- Preconditions.checkNotNull(reason, "CharSequence is null");
- wipeDataInternal(flags, reason.toString());
+ wipeDataInternal(flags, reason != null ? reason.toString() : null);
}
/**
@@ -3469,7 +3468,7 @@ public class DevicePolicyManager {
* @see #wipeData(int, CharSequence)
* @hide
*/
- private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
+ private void wipeDataInternal(int flags, String wipeReasonForUser) {
if (mService != null) {
try {
mService.wipeDataWithReason(flags, wipeReasonForUser);
diff --git a/core/java/android/content/res/package.html b/core/java/android/content/res/package.html
index 3d0bac18d7b7..3970b16a57e1 100644
--- a/core/java/android/content/res/package.html
+++ b/core/java/android/content/res/package.html
@@ -1,7 +1,7 @@
<HTML>
<BODY>
<p>Contains classes for accessing application resources,
-such as raw asset files, colors, drawables, media or other other files
+such as raw asset files, colors, drawables, media, or other files
in the package, plus important device configuration details
(orientation, input types, etc.) that affect how the application may behave.</p>
@@ -9,4 +9,4 @@ in the package, plus important device configuration details
href="{@docRoot}guide/topics/resources/index.html">Application Resources</a> guide.</p>
{@more}
</BODY>
-</HTML> \ No newline at end of file
+</HTML>
diff --git a/core/java/android/hardware/camera2/utils/CloseableLock.java b/core/java/android/hardware/camera2/utils/CloseableLock.java
index 9ac89c825430..3b8beaccdcd9 100644
--- a/core/java/android/hardware/camera2/utils/CloseableLock.java
+++ b/core/java/android/hardware/camera2/utils/CloseableLock.java
@@ -290,7 +290,7 @@ public class CloseableLock implements AutoCloseable {
/**
* Release a single lock that was acquired.
*
- * <p>Any other other that is blocked and trying to acquire a lock will get a chance
+ * <p>Any other thread that is blocked and trying to acquire a lock will get a chance
* to acquire the lock.</p>
*
* @throws IllegalStateException if no locks were acquired, or if the lock was already closed
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b9d900730b69..f947b5ef9f5b 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -773,6 +773,7 @@ public class Binder implements IBinder {
if (tracingEnabled) {
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":" + code);
}
+ ThreadLocalWorkSourceUid.set(Binder.getCallingUid());
res = onTransact(code, data, reply, flags);
} catch (RemoteException|RuntimeException e) {
if (observer != null) {
@@ -793,6 +794,7 @@ public class Binder implements IBinder {
}
res = true;
} finally {
+ ThreadLocalWorkSourceUid.clear();
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index e03af9db1975..f3a9a504a765 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -739,6 +739,8 @@ public class Handler {
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
+ msg.workSourceUid = ThreadLocalWorkSourceUid.get();
+
if (mAsynchronous) {
msg.setAsynchronous(true);
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index ded3a1983fb2..5b8ababb8ca4 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -205,6 +205,7 @@ public final class Looper {
token = observer.messageDispatchStarting();
}
try {
+ ThreadLocalWorkSourceUid.set(msg.workSourceUid);
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
@@ -216,6 +217,7 @@ public final class Looper {
}
throw exception;
} finally {
+ ThreadLocalWorkSourceUid.clear();
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 455d8edd4138..cd3f301ebf08 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,7 +16,6 @@
package android.os;
-import android.os.MessageProto;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -74,11 +73,25 @@ public final class Message implements Parcelable {
public Messenger replyTo;
/**
+ * Indicates that the uid is not set;
+ *
+ * @hide Only for use within the system server.
+ */
+ public static final int UID_NONE = -1;
+
+ /**
* Optional field indicating the uid that sent the message. This is
* only valid for messages posted by a {@link Messenger}; otherwise,
* it will be -1.
*/
- public int sendingUid = -1;
+ public int sendingUid = UID_NONE;
+
+ /**
+ * Optional field indicating the uid that caused this message to be enqueued.
+ *
+ * @hide Only for use within the system server.
+ */
+ public int workSourceUid = UID_NONE;
/** If set message is in use.
* This flag is set when the message is enqueued and remains set while it
@@ -151,6 +164,7 @@ public final class Message implements Parcelable {
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
+ m.workSourceUid = orig.workSourceUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
@@ -301,7 +315,8 @@ public final class Message implements Parcelable {
arg2 = 0;
obj = null;
replyTo = null;
- sendingUid = -1;
+ sendingUid = UID_NONE;
+ workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
@@ -329,6 +344,7 @@ public final class Message implements Parcelable {
this.obj = o.obj;
this.replyTo = o.replyTo;
this.sendingUid = o.sendingUid;
+ this.workSourceUid = o.workSourceUid;
if (o.data != null) {
this.data = (Bundle) o.data.clone();
@@ -612,6 +628,7 @@ public final class Message implements Parcelable {
dest.writeBundle(data);
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
dest.writeInt(sendingUid);
+ dest.writeInt(workSourceUid);
}
private void readFromParcel(Parcel source) {
@@ -625,5 +642,6 @@ public final class Message implements Parcelable {
data = source.readBundle();
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
+ workSourceUid = source.readInt();
}
}
diff --git a/core/java/android/os/ThreadLocalWorkSourceUid.java b/core/java/android/os/ThreadLocalWorkSourceUid.java
new file mode 100644
index 000000000000..df1d275f358d
--- /dev/null
+++ b/core/java/android/os/ThreadLocalWorkSourceUid.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide Only for use within system server.
+ */
+public final class ThreadLocalWorkSourceUid {
+ public static final int UID_NONE = Message.UID_NONE;
+ private static final ThreadLocal<Integer> sWorkSourceUid =
+ ThreadLocal.withInitial(() -> UID_NONE);
+
+ /** Returns the original work source uid. */
+ public static int get() {
+ return sWorkSourceUid.get();
+ }
+
+ /** Sets the original work source uid. */
+ public static void set(int uid) {
+ sWorkSourceUid.set(uid);
+ }
+
+ /** Clears the stored work source uid. */
+ public static void clear() {
+ sWorkSourceUid.set(UID_NONE);
+ }
+
+ private ThreadLocalWorkSourceUid() {
+ }
+}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index e819c963ae45..5012d77568bf 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -146,6 +146,7 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_CONDITION_ID = "conditionId";
private static final String RULE_ATT_CREATION_TIME = "creationTime";
private static final String RULE_ATT_ENABLER = "enabler";
+ private static final String RULE_ATT_MODIFIED = "modified";
@UnsupportedAppUsage
public boolean allowAlarms = DEFAULT_ALLOW_ALARMS;
@@ -633,6 +634,7 @@ public class ZenModeConfig implements Parcelable {
Slog.i(TAG, "Updating zenMode of automatic rule " + rt.name);
rt.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
}
+ rt.modified = safeBoolean(parser, RULE_ATT_MODIFIED, false);
return rt;
}
@@ -656,6 +658,7 @@ public class ZenModeConfig implements Parcelable {
if (rule.condition != null) {
writeConditionXml(rule.condition, out);
}
+ out.attribute(null, RULE_ATT_MODIFIED, Boolean.toString(rule.modified));
}
public static Condition readConditionXml(XmlPullParser parser) {
@@ -1456,6 +1459,7 @@ public class ZenModeConfig implements Parcelable {
public long creationTime; // required for automatic
public String enabler; // package name, only used for manual rules.
public ZenPolicy zenPolicy;
+ public boolean modified; // rule has been modified from initial creation
public ZenRule() { }
@@ -1477,6 +1481,7 @@ public class ZenModeConfig implements Parcelable {
enabler = source.readString();
}
zenPolicy = source.readParcelable(null);
+ modified = source.readInt() == 1;
}
@Override
@@ -1512,6 +1517,7 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(0);
}
dest.writeParcelable(zenPolicy, 0);
+ dest.writeInt(modified ? 1 : 0);
}
@Override
@@ -1528,6 +1534,7 @@ public class ZenModeConfig implements Parcelable {
.append(",creationTime=").append(creationTime)
.append(",enabler=").append(enabler)
.append(",zenPolicy=").append(zenPolicy)
+ .append(",modified=").append(modified)
.append(']').toString();
}
@@ -1554,6 +1561,7 @@ public class ZenModeConfig implements Parcelable {
if (zenPolicy != null) {
zenPolicy.writeToProto(proto, ZenRuleProto.ZEN_POLICY);
}
+ proto.write(ZenRuleProto.MODIFIED, modified);
proto.end(token);
}
@@ -1606,6 +1614,9 @@ public class ZenModeConfig implements Parcelable {
if (!Objects.equals(zenPolicy, to.zenPolicy)) {
d.addLine(item, "zenPolicy", zenPolicy, to.zenPolicy);
}
+ if (modified != to.modified) {
+ d.addLine(item, "modified", modified, to.modified);
+ }
}
@Override
@@ -1622,13 +1633,14 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.component, component)
&& Objects.equals(other.id, id)
&& Objects.equals(other.enabler, enabler)
- && Objects.equals(other.zenPolicy, zenPolicy);
+ && Objects.equals(other.zenPolicy, zenPolicy)
+ && other.modified == modified;
}
@Override
public int hashCode() {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
- component, id, enabler, zenPolicy);
+ component, id, enabler, zenPolicy, modified);
}
public boolean isAutomaticActive() {
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 533d72590f0a..1203541756e8 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -410,11 +410,11 @@ public class ApkSignatureSchemeV2Verifier {
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
- return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+ return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
}
}
- static byte[] generateFsverityRootHash(String apkPath)
+ static byte[] generateApkVerityRootHash(String apkPath)
throws IOException, SignatureNotFoundException, DigestException,
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
@@ -423,7 +423,7 @@ public class ApkSignatureSchemeV2Verifier {
if (vSigner.verityRootHash == null) {
return null;
}
- return ApkVerityBuilder.generateFsverityRootHash(
+ return ApkVerityBuilder.generateApkVerityRootHash(
apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
}
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 758cd2b877f2..939522dcd57f 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -534,11 +534,11 @@ public class ApkSignatureSchemeV3Verifier {
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
- return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+ return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
}
}
- static byte[] generateFsverityRootHash(String apkPath)
+ static byte[] generateApkVerityRootHash(String apkPath)
throws NoSuchAlgorithmException, DigestException, IOException,
SignatureNotFoundException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
@@ -547,7 +547,7 @@ public class ApkSignatureSchemeV3Verifier {
if (vSigner.verityRootHash == null) {
return null;
}
- return ApkVerityBuilder.generateFsverityRootHash(
+ return ApkVerityBuilder.generateApkVerityRootHash(
apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
}
}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index de9f55b09200..a299b11c2b25 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -432,16 +432,16 @@ public class ApkSignatureVerifier {
*
* @return FSverity root hash
*/
- public static byte[] generateFsverityRootHash(String apkPath)
+ public static byte[] generateApkVerityRootHash(String apkPath)
throws NoSuchAlgorithmException, DigestException, IOException {
// first try v3
try {
- return ApkSignatureSchemeV3Verifier.generateFsverityRootHash(apkPath);
+ return ApkSignatureSchemeV3Verifier.generateApkVerityRootHash(apkPath);
} catch (SignatureNotFoundException e) {
// try older version
}
try {
- return ApkSignatureSchemeV2Verifier.generateFsverityRootHash(apkPath);
+ return ApkSignatureSchemeV2Verifier.generateApkVerityRootHash(apkPath);
} catch (SignatureNotFoundException e) {
return null;
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index e247c87fdb4c..081033ae84e9 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -332,7 +332,7 @@ final class ApkSigningBlockUtils {
try {
byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,
apk.length(), signatureInfo);
- ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerity(apk,
+ ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerityTree(apk,
signatureInfo, new ByteBufferFactory() {
@Override
public ByteBuffer create(int capacity) {
@@ -348,26 +348,6 @@ final class ApkSigningBlockUtils {
}
/**
- * Generates the fsverity header and hash tree to be used by kernel for the given apk. This
- * method does not check whether the root hash exists in the Signing Block or not.
- *
- * <p>The output is stored in the {@link ByteBuffer} created by the given {@link
- * ByteBufferFactory}.
- *
- * @return the root hash of the generated hash tree.
- */
- public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory,
- SignatureInfo signatureInfo)
- throws IOException, SignatureNotFoundException, SecurityException, DigestException,
- NoSuchAlgorithmException {
- try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
- ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateApkVerity(apk,
- signatureInfo, bufferFactory);
- return result.rootHash;
- }
- }
-
- /**
* Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
*
* @throws IOException if an I/O error occurs while reading the file.
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 2dd0117d583d..553511d73670 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -16,6 +16,9 @@
package android.util.apk;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
@@ -26,8 +29,10 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
/**
- * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the
- * kernel to verity the APK content on access.
+ * ApkVerityBuilder builds the APK verity tree and the verity header. The generated tree format can
+ * be stored on disk for apk-verity setup and used by kernel. Note that since the current
+ * implementation is different from the upstream, we call this implementation apk-verity instead of
+ * fs-verity.
*
* <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
* the existing APK format, it has to skip APK Signing Block and also has some special treatment for
@@ -47,26 +52,28 @@ abstract class ApkVerityBuilder {
private static final byte[] DEFAULT_SALT = new byte[8];
static class ApkVerityResult {
- public final ByteBuffer fsverityData;
+ public final ByteBuffer verityData;
+ public final int merkleTreeSize;
public final byte[] rootHash;
- ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) {
- this.fsverityData = fsverityData;
+ ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {
+ this.verityData = verityData;
+ this.merkleTreeSize = merkleTreeSize;
this.rootHash = rootHash;
}
}
/**
- * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the
- * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is
- * ready to be appended to the target file to set up fsverity. For fsverity to work, this data
- * must be placed at the next page boundary, and the caller must add additional padding in that
- * case.
+ * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
+ * ByteBuffer} created by the {@link ByteBufferFactory}. The Merkle tree is suitable to be used
+ * as the on-disk format for apk-verity.
*
- * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree.
+ * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
+ * front, the tree size, and the calculated root hash.
*/
- static ApkVerityResult generateApkVerity(RandomAccessFile apk,
- SignatureInfo signatureInfo, ByteBufferFactory bufferFactory)
+ @NonNull
+ static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
+ @Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
long signingBlockSize =
signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
@@ -76,86 +83,69 @@ abstract class ApkVerityBuilder {
ByteBuffer output = bufferFactory.create(
merkleTreeSize
- + CHUNK_SIZE_BYTES); // maximum size of fsverity metadata
+ + CHUNK_SIZE_BYTES); // maximum size of apk-verity metadata
output.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer tree = slice(output, 0, merkleTreeSize);
- ByteBuffer header = slice(output, merkleTreeSize,
- merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES);
- ByteBuffer extensions = slice(output, merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES,
- merkleTreeSize + CHUNK_SIZE_BYTES);
- byte[] apkDigestBytes = new byte[DIGEST_SIZE_BYTES];
- ByteBuffer apkDigest = ByteBuffer.wrap(apkDigestBytes);
- apkDigest.order(ByteOrder.LITTLE_ENDIAN);
-
- // NB: Buffer limit is set inside once finished.
- calculateFsveritySignatureInternal(apk, signatureInfo, tree, apkDigest, header, extensions);
-
- // Put the reverse offset to fs-verity header at the end.
- output.position(merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES + extensions.limit());
- output.putInt(FSVERITY_HEADER_SIZE_BYTES + extensions.limit()
- + 4); // size of this integer right before EOF
- output.flip();
-
- return new ApkVerityResult(output, apkDigestBytes);
+ byte[] apkRootHash = generateApkVerityTreeInternal(apk, signatureInfo, DEFAULT_SALT,
+ levelOffset, tree);
+ return new ApkVerityResult(output, merkleTreeSize, apkRootHash);
+ }
+
+ static void generateApkVerityFooter(@NonNull RandomAccessFile apk,
+ @NonNull SignatureInfo signatureInfo, @NonNull ByteBuffer footerOutput)
+ throws IOException {
+ footerOutput.order(ByteOrder.LITTLE_ENDIAN);
+ generateApkVerityHeader(footerOutput, apk.length(), DEFAULT_SALT);
+ long signingBlockSize =
+ signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+ generateApkVerityExtensions(footerOutput, signatureInfo.apkSigningBlockOffset,
+ signingBlockSize, signatureInfo.eocdOffset);
}
/**
- * Calculates the fsverity root hash for integrity measurement. This needs to be consistent to
- * what kernel returns.
+ * Calculates the apk-verity root hash for integrity measurement. This needs to be consistent
+ * to what kernel returns.
*/
- static byte[] generateFsverityRootHash(RandomAccessFile apk, ByteBuffer apkDigest,
- SignatureInfo signatureInfo)
+ @NonNull
+ static byte[] generateApkVerityRootHash(@NonNull RandomAccessFile apk,
+ @NonNull ByteBuffer apkDigest, @NonNull SignatureInfo signatureInfo)
throws NoSuchAlgorithmException, DigestException, IOException {
- ByteBuffer verityBlock = ByteBuffer.allocate(CHUNK_SIZE_BYTES)
- .order(ByteOrder.LITTLE_ENDIAN);
- ByteBuffer header = slice(verityBlock, 0, FSVERITY_HEADER_SIZE_BYTES);
- ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES,
- CHUNK_SIZE_BYTES - FSVERITY_HEADER_SIZE_BYTES);
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
- calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);
+ ByteBuffer footer = ByteBuffer.allocate(CHUNK_SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN);
+ generateApkVerityFooter(apk, signatureInfo, footer);
+ footer.flip();
MessageDigest md = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
- md.update(header);
- md.update(extensions);
+ md.update(footer);
md.update(apkDigest);
return md.digest();
}
/**
- * Internal method to generate various parts of FSVerity constructs, including the header,
- * extensions, Merkle tree, and the tree's root hash. The output buffer is flipped to the
- * generated data size and is readey for consuming.
+ * Generates the apk-verity header and hash tree to be used by kernel for the given apk. This
+ * method does not check whether the root hash exists in the Signing Block or not.
+ *
+ * <p>The output is stored in the {@link ByteBuffer} created by the given {@link
+ * ByteBufferFactory}.
+ *
+ * @return the root hash of the generated hash tree.
*/
- private static void calculateFsveritySignatureInternal(
- RandomAccessFile apk, SignatureInfo signatureInfo, ByteBuffer treeOutput,
- ByteBuffer rootHashOutput, ByteBuffer headerOutput, ByteBuffer extensionsOutput)
- throws IOException, NoSuchAlgorithmException, DigestException {
- assertSigningBlockAlignedAndHasFullPages(signatureInfo);
- long signingBlockSize =
- signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
- long dataSize = apk.length() - signingBlockSize;
- int[] levelOffset = calculateVerityLevelOffset(dataSize);
-
- if (treeOutput != null) {
- byte[] apkRootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT,
- levelOffset, treeOutput);
- if (rootHashOutput != null) {
- rootHashOutput.put(apkRootHash);
- rootHashOutput.flip();
- }
- }
-
- if (headerOutput != null) {
- headerOutput.order(ByteOrder.LITTLE_ENDIAN);
- generateFsverityHeader(headerOutput, apk.length(), levelOffset.length - 1,
- DEFAULT_SALT);
- }
-
- if (extensionsOutput != null) {
- extensionsOutput.order(ByteOrder.LITTLE_ENDIAN);
- generateFsverityExtensions(extensionsOutput, signatureInfo.apkSigningBlockOffset,
- signingBlockSize, signatureInfo.eocdOffset);
+ @NonNull
+ static byte[] generateApkVerity(@NonNull String apkPath,
+ @NonNull ByteBufferFactory bufferFactory, @NonNull SignatureInfo signatureInfo)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ ApkVerityResult result = generateApkVerityTree(apk, signatureInfo, bufferFactory);
+ ByteBuffer footer = slice(result.verityData, result.merkleTreeSize,
+ result.verityData.limit());
+ generateApkVerityFooter(apk, signatureInfo, footer);
+ // Put the reverse offset to apk-verity header at the end.
+ footer.putInt(footer.position() + 4);
+ result.verityData.limit(result.merkleTreeSize + footer.position());
+ return result.rootHash;
}
}
@@ -297,9 +287,13 @@ abstract class ApkVerityBuilder {
digester.fillUpLastOutputChunk();
}
- private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo,
- byte[] salt, int[] levelOffset, ByteBuffer output)
+ @NonNull
+ private static byte[] generateApkVerityTreeInternal(@NonNull RandomAccessFile apk,
+ @Nullable SignatureInfo signatureInfo, @NonNull byte[] salt,
+ @NonNull int[] levelOffset, @NonNull ByteBuffer output)
throws IOException, NoSuchAlgorithmException, DigestException {
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+
// 1. Digest the apk to generate the leaf level hashes.
generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
@@ -324,7 +318,7 @@ abstract class ApkVerityBuilder {
return rootHash;
}
- private static ByteBuffer generateFsverityHeader(ByteBuffer buffer, long fileSize, int depth,
+ private static ByteBuffer generateApkVerityHeader(ByteBuffer buffer, long fileSize,
byte[] salt) {
if (salt.length != 8) {
throw new IllegalArgumentException("salt is not 8 bytes long");
@@ -351,13 +345,12 @@ abstract class ApkVerityBuilder {
buffer.put(salt); // salt (8 bytes)
skip(buffer, 22); // reserved
- buffer.flip();
return buffer;
}
- private static ByteBuffer generateFsverityExtensions(ByteBuffer buffer, long signingBlockOffset,
- long signingBlockSize, long eocdOffset) {
- // Snapshot of the FSVerity structs (subject to change once upstreamed).
+ private static ByteBuffer generateApkVerityExtensions(ByteBuffer buffer,
+ long signingBlockOffset, long signingBlockSize, long eocdOffset) {
+ // Snapshot of the experimental fs-verity structs (different from upstream).
//
// struct fsverity_extension_elide {
// __le64 offset;
@@ -409,7 +402,6 @@ abstract class ApkVerityBuilder {
skip(buffer, kPadding); // padding
}
- buffer.flip();
return buffer;
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bfe1e95dbaed..3bab87aea644 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -17,8 +17,6 @@
package android.view;
import com.android.internal.os.IResultReceiver;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -71,8 +69,7 @@ interface IWindowManager
boolean stopViewServer(); // Transaction #2
boolean isViewServerRunning(); // Transaction #3
- IWindowSession openSession(in IWindowSessionCallback callback, in IInputMethodClient client,
- in IInputContext inputContext);
+ IWindowSession openSession(in IWindowSessionCallback callback);
void getInitialDisplaySize(int displayId, out Point size);
void getBaseDisplaySize(int displayId, out Point size);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 79eafa80454a..7271a9e4616f 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -70,15 +70,8 @@ public class SurfaceControl implements Parcelable {
private static native void nativeDestroy(long nativeObject);
private static native void nativeDisconnect(long nativeObject);
- private static native Bitmap nativeScreenshot(IBinder displayToken,
- Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
- boolean allLayers, boolean useIdentityTransform, int rotation);
- private static native GraphicBuffer nativeScreenshotToBuffer(IBinder displayToken,
- Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
- boolean allLayers, boolean useIdentityTransform, int rotation);
- private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
- Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
- boolean allLayers, boolean useIdentityTransform);
+ private static native GraphicBuffer nativeScreenshot(IBinder displayToken,
+ Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation);
private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken,
Rect sourceCrop, float frameScale);
@@ -1189,52 +1182,39 @@ public class SurfaceControl implements Parcelable {
}
/**
- * Copy the current screen contents into the provided {@link Surface}
- *
- * @param display The display to take the screenshot of.
- * @param consumer The {@link Surface} to take the screenshot into.
- * @param width The desired width of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param height The desired height of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param minLayer The lowest (bottom-most Z order) surface layer to
- * include in the screenshot.
- * @param maxLayer The highest (top-most Z order) surface layer to
- * include in the screenshot.
- * @param useIdentityTransform Replace whatever transformation (rotation,
- * scaling, translation) the surface layers are currently using with the
- * identity transformation while taking the screenshot.
+ * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
*/
- public static void screenshot(IBinder display, Surface consumer,
- int width, int height, int minLayer, int maxLayer,
- boolean useIdentityTransform) {
- screenshot(display, consumer, new Rect(), width, height, minLayer, maxLayer,
- false, useIdentityTransform);
+ public static void screenshot(IBinder display, Surface consumer) {
+ screenshot(display, consumer, new Rect(), 0, 0, false, 0);
}
/**
* Copy the current screen contents into the provided {@link Surface}
*
- * @param display The display to take the screenshot of.
* @param consumer The {@link Surface} to take the screenshot into.
- * @param width The desired width of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param height The desired height of the returned bitmap; the raw
- * screen will be scaled down to this size.
+ * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
*/
- public static void screenshot(IBinder display, Surface consumer,
- int width, int height) {
- screenshot(display, consumer, new Rect(), width, height, 0, 0, true, false);
+ public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
+ int height, boolean useIdentityTransform, int rotation) {
+ if (consumer == null) {
+ throw new IllegalArgumentException("consumer must not be null");
+ }
+
+ final GraphicBuffer buffer = screenshotToBuffer(display, sourceCrop, width, height,
+ useIdentityTransform, rotation);
+ try {
+ consumer.attachAndQueueBuffer(buffer);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failed to take screenshot - " + e.getMessage());
+ }
}
/**
- * Copy the current screen contents into the provided {@link Surface}
- *
- * @param display The display to take the screenshot of.
- * @param consumer The {@link Surface} to take the screenshot into.
+ * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
*/
- public static void screenshot(IBinder display, Surface consumer) {
- screenshot(display, consumer, new Rect(), 0, 0, 0, 0, true, false);
+ @UnsupportedAppUsage
+ public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
+ return screenshot(sourceCrop, width, height, false, rotation);
}
/**
@@ -1242,79 +1222,16 @@ public class SurfaceControl implements Parcelable {
* Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into
* a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
*
- * CAVEAT: Versions of screenshot that return a {@link Bitmap} can
- * be extremely slow; avoid use unless absolutely necessary; prefer
- * the versions that use a {@link Surface} instead, such as
- * {@link SurfaceControl#screenshot(IBinder, Surface)}.
+ * CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use
+ * unless absolutely necessary; prefer the versions that use a {@link Surface} such as
+ * {@link SurfaceControl#screenshot(IBinder, Surface)} or {@link GraphicBuffer} such as
+ * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
*
- * @param sourceCrop The portion of the screen to capture into the Bitmap;
- * caller may pass in 'new Rect()' if no cropping is desired.
- * @param width The desired width of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param height The desired height of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param minLayer The lowest (bottom-most Z order) surface layer to
- * include in the screenshot.
- * @param maxLayer The highest (top-most Z order) surface layer to
- * include in the screenshot.
- * @param useIdentityTransform Replace whatever transformation (rotation,
- * scaling, translation) the surface layers are currently using with the
- * identity transformation while taking the screenshot.
- * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
- * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take
- * screenshots in its native portrait orientation by default, so this is
- * useful for returning screenshots that are independent of device
- * orientation.
- * @return Returns a hardware Bitmap containing the screen contents, or null
- * if an error occurs. Make sure to call Bitmap.recycle() as soon as
- * possible, once its content is not needed anymore.
+ * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
*/
@UnsupportedAppUsage
public static Bitmap screenshot(Rect sourceCrop, int width, int height,
- int minLayer, int maxLayer, boolean useIdentityTransform,
- int rotation) {
- // TODO: should take the display as a parameter
- IBinder displayToken = SurfaceControl.getBuiltInDisplay(
- SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
- return nativeScreenshot(displayToken, sourceCrop, width, height,
- minLayer, maxLayer, false, useIdentityTransform, rotation);
- }
-
- /**
- * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)}
- * but returns a GraphicBuffer.
- */
- public static GraphicBuffer screenshotToBuffer(Rect sourceCrop, int width, int height,
- int minLayer, int maxLayer, boolean useIdentityTransform,
- int rotation) {
- IBinder displayToken = SurfaceControl.getBuiltInDisplay(
- SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
- return nativeScreenshotToBuffer(displayToken, sourceCrop, width, height,
- minLayer, maxLayer, false, useIdentityTransform, rotation);
- }
-
- /**
- * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)} but
- * includes all Surfaces in the screenshot. This will also update the orientation so it
- * sends the correct coordinates to SF based on the rotation value.
- *
- * @param sourceCrop The portion of the screen to capture into the Bitmap;
- * caller may pass in 'new Rect()' if no cropping is desired.
- * @param width The desired width of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param height The desired height of the returned bitmap; the raw
- * screen will be scaled down to this size.
- * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
- * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take
- * screenshots in its native portrait orientation by default, so this is
- * useful for returning screenshots that are independent of device
- * orientation.
- * @return Returns a Bitmap containing the screen contents, or null
- * if an error occurs. Make sure to call Bitmap.recycle() as soon as
- * possible, once its content is not needed anymore.
- */
- @UnsupportedAppUsage
- public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
+ boolean useIdentityTransform, int rotation) {
// TODO: should take the display as a parameter
IBinder displayToken = SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
@@ -1323,22 +1240,45 @@ public class SurfaceControl implements Parcelable {
}
SurfaceControl.rotateCropForSF(sourceCrop, rotation);
- return nativeScreenshot(displayToken, sourceCrop, width, height, 0, 0, true,
- false, rotation);
+ final GraphicBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width, height,
+ useIdentityTransform, rotation);
+
+ if (buffer == null) {
+ Log.w(TAG, "Failed to take screenshot");
+ return null;
+ }
+ return Bitmap.createHardwareBitmap(buffer);
}
- @UnsupportedAppUsage
- private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop,
- int width, int height, int minLayer, int maxLayer, boolean allLayers,
- boolean useIdentityTransform) {
+ /**
+ * Captures all the surfaces in a display and returns a {@link GraphicBuffer} with the content.
+ *
+ * @param display The display to take the screenshot of.
+ * @param sourceCrop The portion of the screen to capture into the Bitmap; caller may
+ * pass in 'new Rect()' if no cropping is desired.
+ * @param width The desired width of the returned bitmap; the raw screen will be
+ * scaled down to this size; caller may pass in 0 if no scaling is
+ * desired.
+ * @param height The desired height of the returned bitmap; the raw screen will
+ * be scaled down to this size; caller may pass in 0 if no scaling
+ * is desired.
+ * @param useIdentityTransform Replace whatever transformation (rotation, scaling, translation)
+ * the surface layers are currently using with the identity
+ * transformation while taking the screenshot.
+ * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
+ * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take
+ * screenshots in its native portrait orientation by default, so
+ * this is useful for returning screenshots that are independent of
+ * device orientation.
+ * @return Returns a GraphicBuffer that contains the captured content.
+ */
+ public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width,
+ int height, boolean useIdentityTransform, int rotation) {
if (display == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- if (consumer == null) {
- throw new IllegalArgumentException("consumer must not be null");
- }
- nativeScreenshot(display, consumer, sourceCrop, width, height,
- minLayer, maxLayer, allLayers, useIdentityTransform);
+
+ return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation);
}
private static void rotateCropForSF(Rect crop, int rot) {
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index e20acf1a0008..92d145c3bdeb 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -196,7 +196,11 @@ public final class WindowManagerGlobal {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
- InputMethodManager imm = InputMethodManager.getInstance();
+ if (InputMethodManager.ENABLE_LEGACY_EAGER_INITIALIZATION) {
+ // Emulate the legacy behavior. The global instance of InputMethodManager
+ // was instantiated here.
+ InputMethodManager.getInstance();
+ }
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@@ -204,8 +208,7 @@ public final class WindowManagerGlobal {
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
- },
- imm.getClient(), imm.getInputContext());
+ });
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index f89743c149b1..2d1249df4fb5 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -41,8 +41,8 @@ public class DecelerateInterpolator extends BaseInterpolator implements NativeIn
* Constructor
*
* @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
- * an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
- * ease-out effect (i.e., it starts even faster and ends evens slower)
+ * an upside-down y=x^2 parabola. Increasing factor above 1.0f exaggerates the
+ * ease-out effect (i.e., it starts even faster and ends evens slower).
*/
public DecelerateInterpolator(float factor) {
mFactor = factor;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index be50dd1f1448..9ede57f96177 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -225,6 +225,44 @@ public final class InputMethodManager {
static final String PENDING_EVENT_COUNTER = "aq:imm";
+ /**
+ * {@code true} if we want to instantiate {@link InputMethodManager} eagerly in
+ * {@link android.view.WindowManagerGlobal#getWindowSession()}, which is often called in an
+ * early stage of process startup, which is how Android has worked.
+ *
+ * <p>We still have this settings because we know there are possible compatibility concerns if
+ * we stop doing so. Here are scenarios we know and there could be more scenarios we are not
+ * aware of right know.</p>
+ *
+ * <ul>
+ * <li>Apps that directly access {@link #sInstance} via reflection, which is currently
+ * allowed because of {@link UnsupportedAppUsage} annotation. Currently
+ * {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
+ * {@link #sInstance} is not {@code null} when such an app is accessing it, but removing
+ * that code from {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal
+ * untested code paths in their apps, which probably happen in an early startup time of that
+ * app.</li>
+ * <li>Apps that directly access {@link #peekInstance()} via reflection, which is currently
+ * allowed because of {@link UnsupportedAppUsage} annotation. Currently
+ * {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
+ * {@link #peekInstance()} returns non-{@code null} object when such an app is calling
+ * {@link #peekInstance()}, but removing that code from
+ * {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal untested code
+ * paths in their apps, which probably happen in an early startup time of that app. The good
+ * news is that unlike {@link #sInstance}'s case we can at least work around this scenario
+ * by changing the semantics of {@link #peekInstance()}, which is currently defined as
+ * "retrieve the global {@link InputMethodManager} instance, if it exists" to something that
+ * always returns non-{@code null} {@link InputMethodManager}. However, introducing such an
+ * workaround can also trigger different compatibility issues if {@link #peekInstance()} was
+ * called before {@link android.view.WindowManagerGlobal#getWindowSession()} and it expected
+ * {@link #peekInstance()} to return {@code null} as written in the JavaDoc.</li>
+ * </ul>
+ *
+ * <p>TODO(Bug 116157766): Check if we can set {@code false} here then remove this settings.</p>
+ * @hide
+ */
+ public static final boolean ENABLE_LEGACY_EAGER_INITIALIZATION = true;
+
@UnsupportedAppUsage
static InputMethodManager sInstance;
@@ -651,8 +689,10 @@ public final class InputMethodManager {
synchronized (InputMethodManager.class) {
if (sInstance == null) {
try {
- sInstance = new InputMethodManager(Looper.getMainLooper());
- } catch (ServiceNotFoundException e) {
+ final InputMethodManager imm = new InputMethodManager(Looper.getMainLooper());
+ imm.mService.addClient(imm.mClient, imm.mIInputContext);
+ sInstance = imm;
+ } catch (ServiceNotFoundException | RemoteException e) {
throw new IllegalStateException(e);
}
}
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index 05c0304e042c..30f465cb42c6 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -36,7 +36,7 @@ import java.util.concurrent.Executor;
* <pre class="prettyprint">
* TracingController tracingController = TracingController.getInstance();
* tracingController.start(new TracingConfig.Builder()
- * .addCategories(CATEGORIES_WEB_DEVELOPER).build());
+ * .addCategories(TracingConfig.CATEGORIES_WEB_DEVELOPER).build());
* ...
* tracingController.stop(new FileOutputStream("trace.json"),
* Executors.newSingleThreadExecutor());
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 0650d0af7caf..e4724ff45b9e 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -17,6 +17,7 @@
package com.android.internal.os;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -36,7 +37,7 @@ import java.util.concurrent.ThreadLocalRandom;
* @hide Only for use within the system server.
*/
public class LooperStats implements Looper.Observer {
- private static final int TOKEN_POOL_SIZE = 50;
+ private static final int SESSION_POOL_SIZE = 50;
@GuardedBy("mLock")
private final SparseArray<Entry> mEntries = new SparseArray<>(512);
@@ -78,17 +79,19 @@ public class LooperStats implements Looper.Observer {
}
DispatchSession session = (DispatchSession) token;
- Entry entry = getOrCreateEntry(msg);
- synchronized (entry) {
- entry.messageCount++;
- if (session != DispatchSession.NOT_SAMPLED) {
- entry.recordedMessageCount++;
- long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
- long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
- entry.totalLatencyMicro += latency;
- entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
- entry.cpuUsageMicro += cpuUsage;
- entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+ Entry entry = findEntry(msg, /* allowCreateNew= */session != DispatchSession.NOT_SAMPLED);
+ if (entry != null) {
+ synchronized (entry) {
+ entry.messageCount++;
+ if (session != DispatchSession.NOT_SAMPLED) {
+ entry.recordedMessageCount++;
+ long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
+ long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
+ entry.totalLatencyMicro += latency;
+ entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
+ entry.cpuUsageMicro += cpuUsage;
+ entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+ }
}
}
@@ -102,7 +105,7 @@ public class LooperStats implements Looper.Observer {
}
DispatchSession session = (DispatchSession) token;
- Entry entry = getOrCreateEntry(msg);
+ Entry entry = findEntry(msg, /* allowCreateNew= */true);
synchronized (entry) {
entry.exceptionCount++;
}
@@ -159,24 +162,28 @@ public class LooperStats implements Looper.Observer {
mSamplingInterval = samplingInterval;
}
- @NonNull
- private Entry getOrCreateEntry(Message msg) {
+ @Nullable
+ private Entry findEntry(Message msg, boolean allowCreateNew) {
final boolean isInteractive = mDeviceState.isScreenInteractive();
final int id = Entry.idFor(msg, isInteractive);
Entry entry;
synchronized (mLock) {
entry = mEntries.get(id);
if (entry == null) {
- if (mEntries.size() >= mEntriesSizeCap) {
- // If over the size cap, track totals under a single entry.
+ if (!allowCreateNew) {
+ return null;
+ } else if (mEntries.size() >= mEntriesSizeCap) {
+ // If over the size cap track totals under OVERFLOW entry.
return mOverflowEntry;
+ } else {
+ entry = new Entry(msg, isInteractive);
+ mEntries.put(id, entry);
}
- entry = new Entry(msg, isInteractive);
- mEntries.put(id, entry);
}
}
- if (entry.handler.getClass() != msg.getTarget().getClass()
+ if (entry.workSourceUid != msg.workSourceUid
+ || entry.handler.getClass() != msg.getTarget().getClass()
|| entry.handler.getLooper().getThread() != msg.getTarget().getLooper().getThread()
|| entry.isInteractive != isInteractive) {
// If a hash collision happened, track totals under a single entry.
@@ -186,7 +193,7 @@ public class LooperStats implements Looper.Observer {
}
private void recycleSession(DispatchSession session) {
- if (session != DispatchSession.NOT_SAMPLED && mSessionPool.size() < TOKEN_POOL_SIZE) {
+ if (session != DispatchSession.NOT_SAMPLED && mSessionPool.size() < SESSION_POOL_SIZE) {
mSessionPool.add(session);
}
}
@@ -210,6 +217,7 @@ public class LooperStats implements Looper.Observer {
}
private static class Entry {
+ public final int workSourceUid;
public final Handler handler;
public final String messageName;
public final boolean isInteractive;
@@ -222,12 +230,14 @@ public class LooperStats implements Looper.Observer {
public long maxCpuUsageMicro;
Entry(Message msg, boolean isInteractive) {
+ this.workSourceUid = msg.workSourceUid;
this.handler = msg.getTarget();
this.messageName = handler.getMessageName(msg);
this.isInteractive = isInteractive;
}
Entry(String specialEntryName) {
+ this.workSourceUid = Message.UID_NONE;
this.messageName = specialEntryName;
this.handler = null;
this.isInteractive = false;
@@ -245,6 +255,7 @@ public class LooperStats implements Looper.Observer {
static int idFor(Message msg, boolean isInteractive) {
int result = 7;
+ result = 31 * result + msg.workSourceUid;
result = 31 * result + msg.getTarget().getLooper().getThread().hashCode();
result = 31 * result + msg.getTarget().getClass().hashCode();
result = 31 * result + (isInteractive ? 1231 : 1237);
@@ -258,6 +269,7 @@ public class LooperStats implements Looper.Observer {
/** Aggregated data of Looper message dispatching in the in the current process. */
public static class ExportedEntry {
+ public final int workSourceUid;
public final String handlerClassName;
public final String threadName;
public final String messageName;
@@ -271,6 +283,7 @@ public class LooperStats implements Looper.Observer {
public final long maxCpuUsageMicros;
ExportedEntry(Entry entry) {
+ this.workSourceUid = entry.workSourceUid;
if (entry.handler != null) {
this.handlerClassName = entry.handler.getClass().getName();
this.threadName = entry.handler.getLooper().getThread().getName();
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 543f4a532307..5f1243f37542 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -31,6 +31,8 @@ import com.android.internal.view.IInputMethodClient;
* applications.
*/
interface IInputMethodManager {
+ void addClient(in IInputMethodClient client, in IInputContext inputContext);
+
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getInputMethodList();
List<InputMethodInfo> getVrInputMethodList();
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0a252716b69e..0c9a85a92422 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -15,7 +15,6 @@
#include "SkPM4f.h"
#include "SkPM4fPriv.h"
#include "GraphicsJNI.h"
-#include "SkDither.h"
#include "SkUnPreMultiply.h"
#include "SkStream.h"
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 743b9f6e471d..b70177ffab9a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -157,23 +157,17 @@ static Rect rectFromObj(JNIEnv* env, jobject rectObj) {
return Rect(left, top, right, bottom);
}
-static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz,
+static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
- int rotation) {
+ bool useIdentityTransform, int rotation) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken == NULL) {
return NULL;
}
Rect sourceCrop = rectFromObj(env, sourceCropObj);
- if (allLayers) {
- minLayer = INT32_MIN;
- maxLayer = INT32_MAX;
- }
sp<GraphicBuffer> buffer;
- status_t res = ScreenshotClient::capture(displayToken,
- sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform,
- rotation, &buffer);
+ status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
+ useIdentityTransform, rotation, &buffer);
if (res != NO_ERROR) {
return NULL;
}
@@ -187,100 +181,6 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz,
(jlong)buffer.get());
}
-static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
- jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
- int rotation) {
- sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
- if (displayToken == NULL) {
- return NULL;
- }
-
- Rect sourceCrop = rectFromObj(env, sourceCropObj);
-
- std::unique_ptr<ScreenshotClient> screenshot(new ScreenshotClient());
- status_t res;
- if (allLayers) {
- minLayer = INT32_MIN;
- maxLayer = INT32_MAX;
- }
-
- sp<GraphicBuffer> buffer;
- res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
- minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation), &buffer);
- if (res != NO_ERROR) {
- return NULL;
- }
-
- SkColorType colorType;
- SkAlphaType alphaType;
-
- PixelFormat format = buffer->getPixelFormat();
- switch (format) {
- case PIXEL_FORMAT_RGBX_8888: {
- colorType = kRGBA_8888_SkColorType;
- alphaType = kOpaque_SkAlphaType;
- break;
- }
- case PIXEL_FORMAT_RGBA_8888: {
- colorType = kRGBA_8888_SkColorType;
- alphaType = kPremul_SkAlphaType;
- break;
- }
- case PIXEL_FORMAT_RGBA_FP16: {
- colorType = kRGBA_F16_SkColorType;
- alphaType = kPremul_SkAlphaType;
- break;
- }
- case PIXEL_FORMAT_RGB_565: {
- colorType = kRGB_565_SkColorType;
- alphaType = kOpaque_SkAlphaType;
- break;
- }
- default: {
- return NULL;
- }
- }
-
- SkImageInfo info = SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
- colorType, alphaType,
- SkColorSpace::MakeSRGB());
-
- auto bitmap = sk_sp<Bitmap>(new Bitmap(buffer.get(), info));
- return bitmap::createBitmap(env, bitmap.release(),
- android::bitmap::kBitmapCreateFlag_Premultiplied, NULL);
-}
-
-static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
- jobject surfaceObj, jobject sourceCropObj, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
- sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
- if (displayToken == NULL) {
- return;
- }
-
- sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
- if (consumer == NULL) {
- return;
- }
-
- Rect sourceCrop;
- if (sourceCropObj != NULL) {
- sourceCrop = rectFromObj(env, sourceCropObj);
- }
-
- if (allLayers) {
- minLayer = INT32_MIN;
- maxLayer = INT32_MAX;
- }
-
- sp<GraphicBuffer> buffer;
- ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer,
- useIdentityTransform, 0, &buffer);
-
- Surface::attachAndQueueBuffer(consumer.get(), buffer);
-}
-
static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken,
jobject sourceCropObj, jfloat frameScale) {
@@ -919,10 +819,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeDestroy },
{"nativeDisconnect", "(J)V",
(void*)nativeDisconnect },
- {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
- (void*)nativeScreenshotBitmap },
- {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
- (void*)nativeScreenshot },
{"nativeCreateTransaction", "()J",
(void*)nativeCreateTransaction },
{"nativeApplyTransaction", "(JZ)V",
@@ -1013,9 +909,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeDestroyInTransaction },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
- {"nativeScreenshotToBuffer",
- "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;",
- (void*)nativeScreenshotToBuffer },
+ {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZI)Landroid/graphics/GraphicBuffer;",
+ (void*)nativeScreenshot },
{"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
(void*)nativeCaptureLayers },
};
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 8836c2e4241f..c08d7cafd9cc 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -201,6 +201,9 @@ message ZenRuleProto {
optional ConditionProto condition = 9;
optional android.content.ComponentNameProto component = 10;
optional ZenPolicyProto zenPolicy = 11;
+
+ // Indicates whether this ZenRule has been modified after its initial creation
+ optional bool modified = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
// A dump from com.android.server.notification.ZenModeHelper.
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index cb4e5c46b73e..6cf6a8273f5f 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,13 +18,17 @@
-->
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="7">
+<zen version="8">
<allow alarms="true" media="true" system="false" calls="true" callsFrom="2" messages="false"
reminders="false" events="false" repeatCallers="true" />
-
+ <automatic ruleId="EVENTS_DEFAULT_RULE" enabled="false" snoozing="false" name="Event" zen="1"
+ component="android/com.android.server.notification.EventConditionProvider"
+ conditionId="condition://android/event?userId=-10000&amp;calendar=&amp;reply=1"/>
+ <automatic ruleId="EVERY_NIGHT_DEFAULT_RULE" enabled="false" snoozing="false" name="Sleeping"
+ zen="1" component="android/com.android.server.notification.ScheduleConditionProvider"
+ conditionId="condition://android/schedule?days=1.2.3.4.5.6.7&amp;start=22.0&amp;end=7.0&amp;exitAtAlarm=true"/>
<!-- all visual effects that exist as of P -->
<disallow visualEffects="511" />
-
<!-- whether there are notification channels that can bypass dnd -->
<state areChannelsBypassingDnd="false" />
</zen>
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 565a3ecd0411..0c8dd9d6ed59 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.Message;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -74,14 +75,17 @@ public final class LooperStatsTest {
public void testSingleMessageDispatched() {
TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+ Message message = mHandlerFirst.obtainMessage(1000);
+ message.workSourceUid = 1000;
Object token = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
looperStats.tickThreadTime(10);
- looperStats.messageDispatched(token, mHandlerFirst.obtainMessage(1000));
+ looperStats.messageDispatched(token, message);
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
assertThat(entries).hasSize(1);
LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.workSourceUid).isEqualTo(1000);
assertThat(entry.threadName).isEqualTo("TestThread1");
assertThat(entry.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerFirst");
@@ -100,15 +104,17 @@ public final class LooperStatsTest {
public void testThrewException() {
TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+ Message message = mHandlerFirst.obtainMessage(7);
+ message.workSourceUid = 123;
Object token = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
looperStats.tickThreadTime(10);
- looperStats.dispatchingThrewException(token, mHandlerFirst.obtainMessage(7),
- new ArithmeticException());
+ looperStats.dispatchingThrewException(token, message, new ArithmeticException());
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
assertThat(entries).hasSize(1);
LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.workSourceUid).isEqualTo(123);
assertThat(entry.threadName).isEqualTo("TestThread1");
assertThat(entry.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerFirst");
@@ -146,31 +152,39 @@ public final class LooperStatsTest {
looperStats.messageDispatched(token3, mHandlerSecond.obtainMessage().setCallback(() -> {
}));
- // Contributes to entry1.
+ // Will not be sampled so does not contribute to any entries.
Object token4 = looperStats.messageDispatchStarting();
+ looperStats.tickRealtime(10);
+ looperStats.tickThreadTime(10);
+ looperStats.messageDispatched(token4, mHandlerSecond.obtainMessage(0));
+
+ // Contributes to entry1.
+ Object token5 = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
looperStats.tickThreadTime(100);
- looperStats.messageDispatched(token4, mHandlerAnonymous.obtainMessage(1));
+ looperStats.messageDispatched(token5, mHandlerAnonymous.obtainMessage(1));
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
assertThat(entries).hasSize(3);
entries.sort(Comparator.comparing(e -> e.handlerClassName));
- // Captures data for token4 call.
+ // Captures data for token5 call.
LooperStats.ExportedEntry entry1 = entries.get(0);
+ assertThat(entry1.workSourceUid).isEqualTo(-1);
assertThat(entry1.threadName).isEqualTo("TestThread1");
assertThat(entry1.handlerClassName).isEqualTo("com.android.internal.os.LooperStatsTest$1");
assertThat(entry1.messageName).isEqualTo("0x1" /* 1 in hex */);
assertThat(entry1.messageCount).isEqualTo(1);
- assertThat(entry1.recordedMessageCount).isEqualTo(0);
+ assertThat(entry1.recordedMessageCount).isEqualTo(1);
assertThat(entry1.exceptionCount).isEqualTo(0);
- assertThat(entry1.totalLatencyMicros).isEqualTo(0);
- assertThat(entry1.maxLatencyMicros).isEqualTo(0);
- assertThat(entry1.cpuUsageMicros).isEqualTo(0);
- assertThat(entry1.maxCpuUsageMicros).isEqualTo(0);
+ assertThat(entry1.totalLatencyMicros).isEqualTo(100);
+ assertThat(entry1.maxLatencyMicros).isEqualTo(100);
+ assertThat(entry1.cpuUsageMicros).isEqualTo(100);
+ assertThat(entry1.maxCpuUsageMicros).isEqualTo(100);
// Captures data for token1 and token2 calls.
LooperStats.ExportedEntry entry2 = entries.get(1);
+ assertThat(entry2.workSourceUid).isEqualTo(-1);
assertThat(entry2.threadName).isEqualTo("TestThread1");
assertThat(entry2.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerFirst");
@@ -185,6 +199,7 @@ public final class LooperStatsTest {
// Captures data for token3 call.
LooperStats.ExportedEntry entry3 = entries.get(2);
+ assertThat(entry3.workSourceUid).isEqualTo(-1);
assertThat(entry3.threadName).isEqualTo("TestThread2");
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
@@ -265,7 +280,7 @@ public final class LooperStatsTest {
@Test
public void testMessagesOverSizeCap() {
- TestableLooperStats looperStats = new TestableLooperStats(2, 1 /* sizeCap */);
+ TestableLooperStats looperStats = new TestableLooperStats(1, 1 /* sizeCap */);
Object token1 = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
@@ -296,12 +311,12 @@ public final class LooperStatsTest {
assertThat(entry1.handlerClassName).isEqualTo("");
assertThat(entry1.messageName).isEqualTo("OVERFLOW");
assertThat(entry1.messageCount).isEqualTo(3);
- assertThat(entry1.recordedMessageCount).isEqualTo(1);
+ assertThat(entry1.recordedMessageCount).isEqualTo(3);
assertThat(entry1.exceptionCount).isEqualTo(0);
- assertThat(entry1.totalLatencyMicros).isEqualTo(10);
- assertThat(entry1.maxLatencyMicros).isEqualTo(10);
- assertThat(entry1.cpuUsageMicros).isEqualTo(10);
- assertThat(entry1.maxCpuUsageMicros).isEqualTo(10);
+ assertThat(entry1.totalLatencyMicros).isEqualTo(70);
+ assertThat(entry1.maxLatencyMicros).isEqualTo(50);
+ assertThat(entry1.cpuUsageMicros).isEqualTo(40);
+ assertThat(entry1.maxCpuUsageMicros).isEqualTo(20);
LooperStats.ExportedEntry entry2 = entries.get(1);
assertThat(entry2.threadName).isEqualTo("TestThread1");
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index adcdc18ab418..a03b31723808 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -28,6 +28,7 @@
#include <cmath>
#include <log/log.h>
+#include <SkHighContrastFilter.h>
namespace android::uirenderer {
@@ -113,4 +114,20 @@ bool transformPaint(ColorTransform transform, SkPaint* paint) {
return true;
}
+bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) {
+ bool shouldInvert = false;
+ if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) {
+ shouldInvert = true;
+ }
+ if (palette == BitmapPalette::Dark && transform == ColorTransform::Light) {
+ shouldInvert = true;
+ }
+ if (shouldInvert) {
+ SkHighContrastConfig config;
+ config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
+ paint->setColorFilter(SkHighContrastFilter::Make(config)->makeComposed(paint->refColorFilter()));
+ }
+ return shouldInvert;
+}
+
}; // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h
index 32d9a0594879..e723d645e05e 100644
--- a/libs/hwui/CanvasTransform.h
+++ b/libs/hwui/CanvasTransform.h
@@ -16,6 +16,8 @@
#pragma once
+#include "hwui/Bitmap.h"
+
#include <SkCanvas.h>
#include <SkPaintFilterCanvas.h>
@@ -26,6 +28,7 @@ namespace android::uirenderer {
enum class UsageHint {
Unknown = 0,
Background = 1,
+ Foreground = 2,
};
enum class ColorTransform {
@@ -37,4 +40,6 @@ enum class ColorTransform {
// True if the paint was modified, false otherwise
bool transformPaint(ColorTransform transform, SkPaint* paint);
+bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette);
+
} // namespace android::uirenderer; \ No newline at end of file
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3eaff03db369..5f54c025c819 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -278,8 +278,8 @@ struct DrawPicture final : Op {
struct DrawImage final : Op {
static const auto kType = Type::DrawImage;
- DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y, const SkPaint* paint)
- : image(std::move(image)), x(x), y(y) {
+ DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y, const SkPaint* paint, BitmapPalette palette)
+ : image(std::move(image)), x(x), y(y), palette(palette) {
if (paint) {
this->paint = *paint;
}
@@ -287,6 +287,7 @@ struct DrawImage final : Op {
sk_sp<const SkImage> image;
SkScalar x, y;
SkPaint paint;
+ BitmapPalette palette;
void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x, y, &paint); }
};
struct DrawImageNine final : Op {
@@ -309,8 +310,8 @@ struct DrawImageNine final : Op {
struct DrawImageRect final : Op {
static const auto kType = Type::DrawImageRect;
DrawImageRect(sk_sp<const SkImage>&& image, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SkCanvas::SrcRectConstraint constraint)
- : image(std::move(image)), dst(dst), constraint(constraint) {
+ const SkPaint* paint, SkCanvas::SrcRectConstraint constraint, BitmapPalette palette)
+ : image(std::move(image)), dst(dst), constraint(constraint), palette(palette) {
this->src = src ? *src : SkRect::MakeIWH(this->image->width(), this->image->height());
if (paint) {
this->paint = *paint;
@@ -320,6 +321,7 @@ struct DrawImageRect final : Op {
SkRect src, dst;
SkPaint paint;
SkCanvas::SrcRectConstraint constraint;
+ BitmapPalette palette;
void draw(SkCanvas* c, const SkMatrix&) const {
c->drawImageRect(image.get(), src, dst, &paint, constraint);
}
@@ -609,8 +611,8 @@ void DisplayListData::drawPicture(const SkPicture* picture, const SkMatrix* matr
this->push<DrawPicture>(0, picture, matrix, paint);
}
void DisplayListData::drawImage(sk_sp<const SkImage> image, SkScalar x, SkScalar y,
- const SkPaint* paint) {
- this->push<DrawImage>(0, std::move(image), x, y, paint);
+ const SkPaint* paint, BitmapPalette palette) {
+ this->push<DrawImage>(0, std::move(image), x, y, paint, palette);
}
void DisplayListData::drawImageNine(sk_sp<const SkImage> image, const SkIRect& center,
const SkRect& dst, const SkPaint* paint) {
@@ -618,8 +620,8 @@ void DisplayListData::drawImageNine(sk_sp<const SkImage> image, const SkIRect& c
}
void DisplayListData::drawImageRect(sk_sp<const SkImage> image, const SkRect* src,
const SkRect& dst, const SkPaint* paint,
- SkCanvas::SrcRectConstraint constraint) {
- this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint);
+ SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) {
+ this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint, palette);
}
void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Lattice& lattice,
const SkRect& dst, const SkPaint* paint) {
@@ -638,28 +640,33 @@ void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkSca
const SkPaint& paint) {
void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);
copy_v(pod, (const char*)text, bytes);
+ mHasText = true;
}
void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[],
const SkPaint& paint) {
int n = paint.countText(text, bytes);
void* pod = this->push<DrawPosText>(n * sizeof(SkPoint) + bytes, bytes, paint, n);
copy_v(pod, pos, n, (const char*)text, bytes);
+ mHasText = true;
}
void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y,
const SkPaint& paint) {
int n = paint.countText(text, bytes);
void* pod = this->push<DrawPosTextH>(n * sizeof(SkScalar) + bytes, bytes, y, paint, n);
copy_v(pod, xs, n, (const char*)text, bytes);
+ mHasText = true;
}
void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[],
const SkRect* cull, const SkPaint& paint) {
int n = paint.countText(text, bytes);
void* pod = this->push<DrawTextRSXform>(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint);
copy_v(pod, xforms, n, (const char*)text, bytes);
+ mHasText = true;
}
void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
this->push<DrawTextBlob>(0, blob, x, y, paint);
+ mHasText = true;
}
void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4],
@@ -733,20 +740,35 @@ void DisplayListData::reset() {
}
template <class T>
-using has_paint_t = decltype(std::declval<T>().paint);
+using has_paint_helper = decltype(std::declval<T>().paint);
+
+template <class T>
+constexpr bool has_paint = std::experimental::is_detected_v<has_paint_helper, T>;
+
+template <class T>
+using has_palette_helper = decltype(std::declval<T>().palette);
+
+template <class T>
+constexpr bool has_palette = std::experimental::is_detected_v<has_palette_helper, T>;
template <class T>
constexpr color_transform_fn colorTransformForOp() {
- if
- constexpr(std::experimental::is_detected_v<has_paint_t, T>) {
- return [](const void* op, ColorTransform transform) {
- // TODO: We should be const. Or not. Or just use a different map
- // Unclear, but this is the quick fix
- transformPaint(transform,
- const_cast<SkPaint*>(&(reinterpret_cast<const T*>(op)->paint)));
- };
- }
- else {
+ if constexpr(has_paint<T> && has_palette<T>) {
+ // It's a bitmap
+ return [](const void* opRaw, ColorTransform transform) {
+ // TODO: We should be const. Or not. Or just use a different map
+ // Unclear, but this is the quick fix
+ const T* op = reinterpret_cast<const T*>(opRaw);
+ transformPaint(transform, const_cast<SkPaint*>(&(op->paint)), op->palette);
+ };
+ } else if constexpr(has_paint<T>) {
+ return [](const void* opRaw, ColorTransform transform) {
+ // TODO: We should be const. Or not. Or just use a different map
+ // Unclear, but this is the quick fix
+ const T* op = reinterpret_cast<const T*>(opRaw);
+ transformPaint(transform, const_cast<SkPaint*>(&(op->paint)));
+ };
+ } else {
return nullptr;
}
}
@@ -875,7 +897,7 @@ void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala
void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y,
const SkPaint* paint) {
- fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint);
+ fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint, BitmapPalette::Unknown);
}
void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst,
const SkPaint* paint) {
@@ -883,16 +905,26 @@ void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center
}
void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) {
- fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint);
+ fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint, BitmapPalette::Unknown);
}
void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice,
const SkRect& dst, const SkPaint* paint) {
fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint);
}
+void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
+ const SkPaint* paint, BitmapPalette palette) {
+ fDL->drawImage(image, x, y, paint, palette);
+}
+
+void RecordingCanvas::drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette) {
+ fDL->drawImageRect(image, &src, dst, paint, constraint, palette);
+}
+
void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y,
const SkPaint* paint) {
- fDL->drawImage(sk_ref_sp(img), x, y, paint);
+ fDL->drawImage(sk_ref_sp(img), x, y, paint, BitmapPalette::Unknown);
}
void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
const SkPaint* paint) {
@@ -900,7 +932,7 @@ void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center,
}
void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) {
- fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint);
+ fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint, BitmapPalette::Unknown);
}
void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice,
const SkRect& dst, const SkPaint* paint) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 32ce1d333448..eecf51ce0996 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -17,6 +17,7 @@
#pragma once
#include "CanvasTransform.h"
+#include "hwui/Bitmap.h"
#include "hwui/Canvas.h"
#include "utils/Macros.h"
#include "utils/TypeLogic.h"
@@ -53,6 +54,7 @@ class RecordingCanvas;
class DisplayListData final {
public:
+ DisplayListData() : mHasText(false) {}
~DisplayListData();
void draw(SkCanvas* canvas) const;
@@ -62,6 +64,8 @@ public:
void applyColorTransform(ColorTransform transform);
+ bool hasText() const { return mHasText; }
+
private:
friend class RecordingCanvas;
@@ -101,10 +105,10 @@ private:
void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&);
void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&);
- void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*);
+ void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette);
void drawImageNine(sk_sp<const SkImage>, const SkIRect&, const SkRect&, const SkPaint*);
void drawImageRect(sk_sp<const SkImage>, const SkRect*, const SkRect&, const SkPaint*,
- SkCanvas::SrcRectConstraint);
+ SkCanvas::SrcRectConstraint, BitmapPalette palette);
void drawImageLattice(sk_sp<const SkImage>, const SkCanvas::Lattice&, const SkRect&,
const SkPaint*);
@@ -126,6 +130,8 @@ private:
SkAutoTMalloc<uint8_t> fBytes;
size_t fUsed = 0;
size_t fReserved = 0;
+
+ bool mHasText : 1;
};
class RecordingCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
@@ -178,6 +184,12 @@ public:
void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
SrcRectConstraint) override;
+ void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
+ const SkPaint* paint, BitmapPalette pallete);
+
+ void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette);
+
void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 896b4340f1b8..06dbb2410a12 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -272,8 +272,12 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
mStagingDisplayList = nullptr;
if (mDisplayList) {
mDisplayList->syncContents();
+
if (CC_UNLIKELY(Properties::forceDarkMode)) {
auto usage = usageHint();
+ if (mDisplayList->hasText()) {
+ usage = UsageHint::Foreground;
+ }
if (usage == UsageHint::Unknown) {
if (mDisplayList->mChildNodes.size() > 1) {
usage = UsageHint::Background;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 83b0c2278151..211dd2db5cf8 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -107,7 +107,7 @@ public:
bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
bool hasProjectionReceiver() const {
- return mDisplayList && mDisplayList->projectionReceiveIndex >= 0;
+ return mDisplayList && mDisplayList->containsProjectionReceiver();
}
const char* getName() const { return mName.string(); }
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index f1c10d1570a4..9c284531674f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -328,15 +328,6 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) {
*outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
}
-
- // TODO: Move this to the canvas (or other?) layer where we have the target lightness
- // mode and can selectively do the right thing.
- // if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) {
- // SkHighContrastConfig config;
- // config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
- // *outputColorFilter =
- // SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter);
- // }
return image;
}
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 78b64b2f01eb..38905138e332 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -132,7 +132,6 @@ void SkiaDisplayList::reset() {
mChildFunctors.clear();
mChildNodes.clear();
- projectionReceiveIndex = -1;
allocator.~LinearAllocator();
new (&allocator) LinearAllocator();
}
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 4c7853931029..ac7bb7b0950c 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -49,9 +49,6 @@ namespace skiapipeline {
*/
class SkiaDisplayList {
public:
- // index of DisplayListOp restore, after which projected descendants should be drawn
- int projectionReceiveIndex = -1;
-
size_t getUsedSize() { return allocator.usedSize(); }
~SkiaDisplayList() {
@@ -96,6 +93,8 @@ public:
*/
bool hasVectorDrawables() const { return !mVectorDrawables.empty(); }
+ bool hasText() const { return mDisplayList.hasText(); }
+
/**
* Attempts to reset and reuse this DisplayList.
*
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 3c281e78ddd5..3042006e5684 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -113,8 +113,6 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
// use staging property, since recording on UI thread
if (renderNode->stagingProperties().isProjectionReceiver()) {
mDisplayList->mProjectionReceiver = &renderNodeDrawable;
- // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true
- mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1;
}
}
@@ -196,7 +194,7 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint,
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
- mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)));
+ mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)), bitmap.palette());
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
// it is not safe to store a raw SkImage pointer, because the image object will be destroyed
// when this function ends.
@@ -211,7 +209,7 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
- mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)));
+ mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)), bitmap.palette());
if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
}
@@ -226,7 +224,7 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)),
- SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
!dstRect.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
index 335ad5ebcde5..83f05c263f85 100644
--- a/location/java/android/location/Address.java
+++ b/location/java/android/location/Address.java
@@ -363,7 +363,7 @@ public class Address implements Parcelable {
* or null if it is unknown.
*
* @throws IllegalStateException if this Address has not been assigned
- * a latitude.
+ * a phone number.
*/
public String getPhone() {
return mPhone;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 9050b4b0a15b..0dbc037f2298 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -81,7 +81,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private static final long DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS = 20 * DateUtils.MINUTE_IN_MILLIS;
/** Maximum age of scan results to hold onto while actively scanning. **/
- private static final long MAX_SCAN_RESULT_AGE_MILLIS = 25000;
+ private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
private static final String TAG = "WifiTracker";
private static final boolean DBG() {
@@ -134,8 +134,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
/**
* Tracks whether fresh scan results have been received since scanning start.
*
- * <p>If this variable is false, we will not evict the scan result cache or invoke callbacks
- * so that we do not update the UI with stale data / clear out existing UI elements prematurely.
+ * <p>If this variable is false, we will not invoke callbacks so that we do not
+ * update the UI with stale data / clear out existing UI elements prematurely.
*/
private boolean mStaleScanResults = true;
@@ -327,7 +327,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
* <p>Intended to only be invoked within {@link #onStart()}.
*/
@MainThread
- private void forceUpdate() {
+ @VisibleForTesting
+ void forceUpdate() {
mLastInfo = mWifiManager.getConnectionInfo();
mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
@@ -443,10 +444,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mScanResultCache.put(newResult.BSSID, newResult);
}
- // Don't evict old results if no new scan results
- if (!mStaleScanResults) {
- evictOldScans();
- }
+ // Evict old results in all conditions
+ evictOldScans();
ArrayMap<String, List<ScanResult>> scanResultsByApKey = new ArrayMap<>();
for (ScanResult result : mScanResultCache.values()) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 517db78d5dd1..1860b31081e1 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
@@ -104,6 +103,10 @@ public class WifiTrackerTest {
private static final byte SCORE_2 = 15;
private static final int BADGE_2 = AccessPoint.Speed.FAST;
+ private static final String SSID_3 = "ssid3";
+ private static final String BSSID_3 = "CC:00:00:00:00:00";
+ private static final int RSSI_3 = -40;
+
// TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
private static final int NETWORK_ID_1 = 123;
private static final int CONNECTED_RSSI = -50;
@@ -255,6 +258,19 @@ public class WifiTrackerTest {
SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
}
+ private static ScanResult buildStaleScanResult() {
+ return new ScanResult(
+ WifiSsid.createFromAsciiEncoded(SSID_3),
+ BSSID_3,
+ 0, // hessid
+ 0, //anqpDomainId
+ null, // osuProviders
+ "", // capabilities
+ RSSI_3,
+ 0, // frequency
+ 0 /* microsecond timestamp */);
+ }
+
private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
Intent ... intents)
throws InterruptedException {
@@ -896,4 +912,18 @@ public class WifiTrackerTest {
assertThat(aps.get(0).isReachable()).isTrue();
assertThat(aps.get(1).isReachable()).isTrue();
}
+
+ @Test
+ public void onStart_updateScanResults_evictOldScanResult() {
+ when(mockWifiManager.getScanResults()).thenReturn(
+ Arrays.asList(buildScanResult1(), buildScanResult2(), buildStaleScanResult()));
+ WifiTracker tracker = createMockedWifiTracker();
+
+ tracker.forceUpdate();
+
+ // Only has scanResult1 and scanResult2
+ assertThat(tracker.getAccessPoints()).hasSize(2);
+ assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
+ assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
+ }
}
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index 07f0c83e7b2e..a8960d9b9437 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tile_page"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:paddingStart="@dimen/notification_side_paddings"
android:paddingEnd="@dimen/notification_side_paddings"
android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index e96a09baa9db..11a01871b782 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -19,6 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
diff --git a/packages/SystemUI/res/values-h320dp/config.xml b/packages/SystemUI/res/values-h320dp/config.xml
deleted file mode 100644
index a9c19db0f46f..000000000000
--- a/packages/SystemUI/res/values-h320dp/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-
-<resources>
- <!-- The number of rows in the QuickSettings -->
- <integer name="quick_settings_num_rows">2</integer>
-</resources>
diff --git a/packages/SystemUI/res/values-h600dp/config.xml b/packages/SystemUI/res/values-h600dp/config.xml
deleted file mode 100644
index 8616e3e62779..000000000000
--- a/packages/SystemUI/res/values-h600dp/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-
-<resources>
- <!-- The number of rows in the QuickSettings -->
- <integer name="quick_settings_num_rows">3</integer>
-</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 11bd392b7d52..24dcd3e3b70d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -107,7 +107,7 @@
<integer name="quick_settings_num_columns">3</integer>
<!-- The number of rows in the QuickSettings -->
- <integer name="quick_settings_num_rows">1</integer>
+ <integer name="quick_settings_max_rows">3</integer>
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">1</integer>
@@ -146,19 +146,29 @@
<!-- Should "LTE"/"4G" be shown instead of "LTE+"/"4G+" when on NETWORK_TYPE_LTE_CA? -->
<bool name="config_hideLtePlus">false</bool>
- <!-- milliseconds before the heads up notification auto-dismisses. -->
+ <!-- The number of milliseconds before the heads up notification auto-dismisses. -->
<integer name="heads_up_notification_decay">5000</integer>
- <!-- milliseconds after a heads up notification is pushed back
+ <!-- The number of milliseconds after a heads up notification is pushed back
before the app can interrupt again. -->
<integer name="heads_up_default_snooze_length_ms">60000</integer>
<!-- Minimum display time for a heads up notification, in milliseconds. -->
<integer name="heads_up_notification_minimum_time">2000</integer>
- <!-- milliseconds before the heads up notification accepts touches. -->
+ <!-- The number of milliseconds before the heads up notification accepts touches. -->
<integer name="touch_acceptance_delay">700</integer>
+ <!-- The number of milliseconds before the ambient notification auto-dismisses. This will
+ override the default pulse length. -->
+ <integer name="ambient_notification_decay">6000</integer>
+
+ <!-- Minimum display time for a heads up notification, in milliseconds. -->
+ <integer name="ambient_notification_minimum_time">2000</integer>
+
+ <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
+ <integer name="ambient_notification_extension_time">6000</integer>
+
<!-- The duration in seconds to wait before the dismiss buttons are shown. -->
<integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 04d72cec402f..258b6f61d4c0 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -30,6 +30,7 @@ import com.android.systemui.Dependency.DependencyProvider;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -137,6 +138,7 @@ public class SystemUIFactory {
providers.put(NotificationGroupManager.class, NotificationGroupManager::new);
providers.put(NotificationMediaManager.class, () -> new NotificationMediaManager(context));
providers.put(NotificationGutsManager.class, () -> new NotificationGutsManager(context));
+ providers.put(AmbientPulseManager.class, () -> new AmbientPulseManager(context));
providers.put(NotificationBlockingHelperManager.class,
() -> new NotificationBlockingHelperManager(context));
providers.put(NotificationRemoteInputManager.class,
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index d6a1cf082c0d..5739c997d8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -16,7 +16,6 @@
package com.android.systemui.car;
import android.content.Context;
-import android.service.notification.StatusBarNotification;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -41,7 +40,7 @@ public class CarNotificationEntryManager extends NotificationEntryManager {
}
@Override
- public boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn) {
+ public boolean shouldHeadsUp(NotificationData.Entry entry) {
// Because space is usually constrained in the auto use-case, there should not be a
// pinned notification when the shade has been expanded. Ensure this by not pinning any
// notification if the shade is already opened.
@@ -49,6 +48,6 @@ public class CarNotificationEntryManager extends NotificationEntryManager {
return false;
}
- return super.shouldPeek(entry, sbn);
+ return super.shouldHeadsUp(entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 6a29299872a4..bb059809be2b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -48,7 +48,15 @@ public interface DozeHost {
void onIgnoreTouchWhilePulsing(boolean ignore);
interface Callback {
- default void onNotificationHeadsUp() {}
+ /**
+ * Called when a high priority notification is added.
+ */
+ default void onNotificationAlerted() {}
+
+ /**
+ * Called when battery state or power save mode changes.
+ * @param active whether power save is active or not
+ */
default void onPowerSaveChanged(boolean active) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1589969d19c1..31548b93ea60 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -409,7 +409,7 @@ public class DozeTriggers implements DozeMachine.Part {
private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
@Override
- public void onNotificationHeadsUp() {
+ public void onNotificationAlerted() {
onNotification();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1655c01f5e8e..757c821f37e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,9 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
+import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
+import static com.android.internal.telephony.IccCardConstants.State.PUK_REQUIRED;
+import static com.android.internal.telephony.IccCardConstants.State.READY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -30,7 +33,6 @@ import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.hardware.biometrics.BiometricSourceType;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -38,6 +40,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricSourceType;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
@@ -58,6 +61,7 @@ import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
@@ -70,21 +74,21 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -274,6 +278,12 @@ public class KeyguardViewMediator extends SystemUI {
private KeyguardUpdateMonitor mUpdateMonitor;
+ /**
+ * Last SIM state reported by the telephony system.
+ * Index is the slotId - in case of multiple SIM cards.
+ */
+ private final SparseArray<IccCardConstants.State> mLastSimStates = new SparseArray<>();
+
private boolean mDeviceInteractive;
private boolean mGoingToSleep;
@@ -450,6 +460,14 @@ public class KeyguardViewMediator extends SystemUI {
}
}
+ boolean simWasLocked;
+ synchronized (KeyguardViewMediator.this) {
+ IccCardConstants.State lastState = mLastSimStates.get(slotId);
+ simWasLocked = (lastState == PIN_REQUIRED || lastState == PUK_REQUIRED)
+ && simState == READY;
+ mLastSimStates.append(slotId, simState);
+ }
+
switch (simState) {
case NOT_READY:
case ABSENT:
@@ -503,6 +521,9 @@ public class KeyguardViewMediator extends SystemUI {
case READY:
synchronized (KeyguardViewMediator.this) {
if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
+ if (mShowing && simWasLocked) {
+ resetStateLocked();
+ }
mLockWhenSimRemoved = true;
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 123fca71deaf..fcd479ce6627 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,14 +6,12 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
+
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
@@ -41,14 +39,12 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
return t * t * t + 1.0f;
};
-
private final ArrayList<TileRecord> mTiles = new ArrayList<>();
private final ArrayList<TilePage> mPages = new ArrayList<>();
private PageIndicator mPageIndicator;
private float mPageIndicatorPosition;
- private int mNumPages;
private PageListener mPageListener;
private boolean mListening;
@@ -56,6 +52,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
private AnimatorSet mBounceAnimatorSet;
private float mLastExpansion;
+ private boolean mDistributeTiles = false;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -122,7 +119,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
public void setPageIndicator(PageIndicator indicator) {
mPageIndicator = indicator;
- mPageIndicator.setNumPages(mNumPages);
+ mPageIndicator.setNumPages(mPages.size());
mPageIndicator.setLocation(mPageIndicatorPosition);
}
@@ -136,13 +133,15 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
@Override
public void addTile(TileRecord tile) {
mTiles.add(tile);
- postDistributeTiles();
+ mDistributeTiles = true;
+ requestLayout();
}
@Override
public void removeTile(TileRecord tile) {
if (mTiles.remove(tile)) {
- postDistributeTiles();
+ mDistributeTiles = true;
+ requestLayout();
}
}
@@ -175,44 +174,50 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
mPageListener = listener;
}
- private void postDistributeTiles() {
- removeCallbacks(mDistribute);
- post(mDistribute);
- }
-
private void distributeTiles() {
+ emptyAndInflateOrRemovePages();
+
+ final int tileCount = mPages.get(0).maxTiles();
if (DEBUG) Log.d(TAG, "Distributing tiles");
- final int NP = mPages.size();
- for (int i = 0; i < NP; i++) {
- mPages.get(i).removeAllViews();
- }
int index = 0;
final int NT = mTiles.size();
for (int i = 0; i < NT; i++) {
TileRecord tile = mTiles.get(i);
- if (mPages.get(index).isFull()) {
- if (++index == mPages.size()) {
- if (DEBUG) Log.d(TAG, "Adding page for "
- + tile.tile.getClass().getSimpleName());
- mPages.add((TilePage) LayoutInflater.from(getContext())
- .inflate(R.layout.qs_paged_page, this, false));
- }
+ if (mPages.get(index).mRecords.size() == tileCount) index++;
+ if (DEBUG) {
+ Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
+ + index);
}
- if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
- + index);
mPages.get(index).addTile(tile);
}
- if (mNumPages != index + 1) {
- mNumPages = index + 1;
- while (mPages.size() > mNumPages) {
- mPages.remove(mPages.size() - 1);
- }
- if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
- mPageIndicator.setNumPages(mNumPages);
- setAdapter(mAdapter);
- mAdapter.notifyDataSetChanged();
- setCurrentItem(0, false);
+ }
+
+ private void emptyAndInflateOrRemovePages() {
+ final int nTiles = mTiles.size();
+ int numPages = nTiles / mPages.get(0).maxTiles();
+ // Add one more not full page if needed
+ numPages += (nTiles % mPages.get(0).maxTiles() == 0 ? 0 : 1);
+
+ final int NP = mPages.size();
+ for (int i = 0; i < NP; i++) {
+ mPages.get(i).removeAllViews();
}
+ if (NP == numPages) {
+ return;
+ }
+ while (mPages.size() < numPages) {
+ if (DEBUG) Log.d(TAG, "Adding page");
+ mPages.add((TilePage) LayoutInflater.from(getContext())
+ .inflate(R.layout.qs_paged_page, this, false));
+ }
+ while (mPages.size() > numPages) {
+ if (DEBUG) Log.d(TAG, "Removing page");
+ mPages.remove(mPages.size() - 1);
+ }
+ mPageIndicator.setNumPages(mPages.size());
+ setAdapter(mAdapter);
+ mAdapter.notifyDataSetChanged();
+ setCurrentItem(0, false);
}
@Override
@@ -222,20 +227,39 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
setPadding(0, 0, 0,
getContext().getResources().getDimensionPixelSize(
R.dimen.qs_paged_tile_layout_padding_bottom));
-
boolean changed = false;
for (int i = 0; i < mPages.size(); i++) {
changed |= mPages.get(i).updateResources();
}
if (changed) {
- distributeTiles();
+ mDistributeTiles = true;
+ requestLayout();
}
return changed;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+ final int nTiles = mTiles.size();
+ if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+
+ // Only change the pages if the number of rows or columns (from updateResources) has
+ // changed or the tiles have changed
+ if (mPages.get(0).updateMaxRows(heightMeasureSpec, nTiles) || mDistributeTiles) {
+ mDistributeTiles = false;
+ distributeTiles();
+ }
+
+ final int nRows = mPages.get(0).mRows;
+ for (int i = 0; i < mPages.size(); i++) {
+ TilePage t = mPages.get(i);
+ t.mRows = nRows;
+ }
+ }
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
// The ViewPager likes to eat all of the space, instead force it to wrap to the max height
// of the pages.
int maxHeight = 0;
@@ -249,13 +273,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
setMeasuredDimension(getMeasuredWidth(), maxHeight + getPaddingBottom());
}
- private final Runnable mDistribute = new Runnable() {
- @Override
- public void run() {
- distributeTiles();
- }
- };
-
public int getColumnCount() {
if (mPages.size() == 0) return 0;
return mPages.get(0).mColumns;
@@ -346,33 +363,17 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
};
public static class TilePage extends TileLayout {
- private int mMaxRows = 3;
+
public TilePage(Context context, AttributeSet attrs) {
super(context, attrs);
- updateResources();
}
- @Override
- public boolean updateResources() {
- final int rows = getRows();
- boolean changed = rows != mMaxRows;
- if (changed) {
- mMaxRows = rows;
- requestLayout();
- }
- return super.updateResources() || changed;
- }
-
- private int getRows() {
- return Math.max(1, getResources().getInteger(R.integer.quick_settings_num_rows));
- }
-
- public void setMaxRows(int maxRows) {
- mMaxRows = maxRows;
+ public boolean isFull() {
+ return mRecords.size() >= mColumns * mRows;
}
- public boolean isFull() {
- return mRecords.size() >= mColumns * mMaxRows;
+ public int maxTiles() {
+ return mColumns * mRows;
}
}
@@ -401,7 +402,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
@Override
public int getCount() {
- return mNumPages;
+ return mPages.size();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index feff5d4a3cc1..1451e71e2df5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
@@ -91,15 +92,24 @@ public class QSContainerImpl extends FrameLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Since we control our own bottom, be whatever size we want.
- // Otherwise the QSPanel ends up with 0 height when the window is only the
- // size of the status bar.
- mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
+ // QSPanel will show as many rows as it can (up to TileLayout.MAX_ROWS) such that the
+ // bottom and footer are inside the screen.
+ Configuration config = getResources().getConfiguration();
+ boolean navBelow = config.smallestScreenWidthDp >= 600
+ || config.orientation != Configuration.ORIENTATION_LANDSCAPE;
+ MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanel.getLayoutParams();
+
+ // The footer is pinned to the bottom of QSPanel (same bottoms), therefore we don't need to
+ // subtract its height. We do not care if the collapsed notifications fit in the screen.
+ int maxQs = getDisplayHeight() - layoutParams.topMargin - layoutParams.bottomMargin
+ - getPaddingBottom();
+ if (navBelow) {
+ maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
+ }
+ mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
int width = mQSPanel.getMeasuredWidth();
- LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
int height = layoutParams.topMargin + layoutParams.bottomMargin
- + mQSPanel.getMeasuredHeight();
+ + mQSPanel.getMeasuredHeight() + getPaddingBottom();
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index c67165ea95a1..01ff72e6d152 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -24,10 +24,12 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
protected int mCellMarginHorizontal;
protected int mCellMarginVertical;
protected int mSidePadding;
+ protected int mRows = 1;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private int mCellMarginTop;
private boolean mListening;
+ protected int mMaxAllowedRows = 3;
public TileLayout(Context context) {
this(context, null);
@@ -86,6 +88,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
mSidePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_layout_margin_side);
+ mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
if (mColumns != columns) {
mColumns = columns;
requestLayout();
@@ -96,10 +99,16 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // If called with AT_MOST, it will limit the number of rows. If called with UNSPECIFIED
+ // it will show all its tiles. In this case, the tiles have to be entered before the
+ // container is measured. Any change in the tiles, should trigger a remeasure.
final int numTiles = mRecords.size();
final int width = MeasureSpec.getSize(widthMeasureSpec)
- getPaddingStart() - getPaddingEnd();
- final int numRows = (numTiles + mColumns - 1) / mColumns;
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ if (heightMode == MeasureSpec.UNSPECIFIED) {
+ mRows = (numTiles + mColumns - 1) / mColumns;
+ }
mCellWidth = (width - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
// Measure each QS tile.
@@ -112,13 +121,35 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
// Only include the top margin in our measurement if we have more than 1 row to show.
// Otherwise, don't add the extra margin buffer at top.
- int height = (mCellHeight + mCellMarginVertical) * numRows +
- (numRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
+ int height = (mCellHeight + mCellMarginVertical) * mRows +
+ (mRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
if (height < 0) height = 0;
setMeasuredDimension(width, height);
}
+ /**
+ * Determines the maximum number of rows that can be shown based on height. Clips at a minimum
+ * of 1 and a maximum of mMaxAllowedRows.
+ *
+ * @param heightMeasureSpec Available height.
+ * @param tilesCount Upper limit on the number of tiles to show. to prevent empty rows.
+ */
+ public boolean updateMaxRows(int heightMeasureSpec, int tilesCount) {
+ final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop;
+ final int previousRows = mRows;
+ mRows = availableHeight / (mCellHeight + mCellMarginVertical);
+ if (mRows >= mMaxAllowedRows) {
+ mRows = mMaxAllowedRows;
+ } else if (mRows <= 1) {
+ mRows = 1;
+ }
+ if (mRows > (tilesCount + mColumns - 1) / mColumns) {
+ mRows = (tilesCount + mColumns - 1) / mColumns;
+ }
+ return previousRows != mRows;
+ }
+
@Override
public boolean hasOverlappingRendering() {
return false;
@@ -135,7 +166,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
int column = 0;
// Layout each QS tile.
- for (int i = 0; i < numRecords; i++, column++) {
+ final int tilesToLayout = Math.min(numRecords, mRows * mColumns);
+ for (int i = 0; i < tilesToLayout; i++, column++) {
// If we reached the last column available to layout a tile, wrap back to the next row.
if (column == mColumns) {
column = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 45165180e93a..b6e88d6dfc11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -165,7 +165,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
* Whether or not the given notification is alerting and managed by this manager.
* @return true if the notification is alerting
*/
- public boolean contains(@NonNull String key) {
+ public boolean isAlerting(@NonNull String key) {
return mAlertEntries.containsKey(key);
}
@@ -294,7 +294,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
removeAutoRemovalCallbacks();
if (!isSticky()) {
- long finishTime = mPostTime + mAutoDismissNotificationDecay;
+ long finishTime = calculateFinishTime();
long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
mHandler.postDelayed(mRemoveAlertRunnable, removeDelay);
}
@@ -357,6 +357,14 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
protected long calculatePostTime() {
return mClock.currentTimeMillis();
}
+
+ /**
+ * Calculate when the notification should auto-dismiss itself.
+ * @return the finish time
+ */
+ protected long calculateFinishTime() {
+ return mPostTime + mAutoDismissNotificationDecay;
+ }
}
protected final static class Clock {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
new file mode 100644
index 000000000000..2c384d0f4d80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationData;
+
+/**
+ * Manager which handles high priority notifications that should "pulse" in when the device is
+ * dozing and/or in AOD. The pulse uses the notification's ambient view and pops in briefly
+ * before automatically dismissing the alert.
+ */
+public final class AmbientPulseManager extends AlertingNotificationManager {
+
+ protected final ArraySet<OnAmbientChangedListener> mListeners = new ArraySet<>();
+ @VisibleForTesting
+ protected long mExtensionTime;
+
+ public AmbientPulseManager(@NonNull final Context context) {
+ Resources resources = context.getResources();
+ mAutoDismissNotificationDecay = resources.getInteger(R.integer.ambient_notification_decay);
+ mMinimumDisplayTime = resources.getInteger(R.integer.ambient_notification_minimum_time);
+ mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
+ }
+
+ /**
+ * Adds an OnAmbientChangedListener to observe events.
+ */
+ public void addListener(@NonNull OnAmbientChangedListener listener) {
+ mListeners.add(listener);
+ }
+
+ /**
+ * Removes the OnAmbientChangedListener from the observer list.
+ */
+ public void removeListener(@NonNull OnAmbientChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
+ /**
+ * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
+ * longer.
+ */
+ public void extendPulse() {
+ AmbientEntry topEntry = getTopEntry();
+ if (topEntry == null) {
+ return;
+ }
+ topEntry.extendPulse();
+ }
+
+ @Override
+ protected void onAlertEntryAdded(AlertEntry alertEntry) {
+ NotificationData.Entry entry = alertEntry.mEntry;
+ entry.row.setAmbientPulsing(true);
+ for (OnAmbientChangedListener listener : mListeners) {
+ listener.onAmbientStateChanged(entry, true);
+ }
+ }
+
+ @Override
+ protected void onAlertEntryRemoved(AlertEntry alertEntry) {
+ NotificationData.Entry entry = alertEntry.mEntry;
+ entry.row.setAmbientPulsing(false);
+ for (OnAmbientChangedListener listener : mListeners) {
+ listener.onAmbientStateChanged(entry, false);
+ }
+ }
+
+ @Override
+ protected AlertEntry createAlertEntry() {
+ return new AmbientEntry();
+ }
+
+ /**
+ * Get the top pulsing entry. This should be the currently showing one if there are multiple.
+ * @return the currently showing entry
+ */
+ private AmbientEntry getTopEntry() {
+ if (mAlertEntries.isEmpty()) {
+ return null;
+ }
+ AlertEntry topEntry = null;
+ for (AlertEntry entry : mAlertEntries.values()) {
+ if (topEntry == null || entry.compareTo(topEntry) < 0) {
+ topEntry = entry;
+ }
+ }
+ return (AmbientEntry) topEntry;
+ }
+
+ /**
+ * Observer interface for any changes in the ambient entries.
+ */
+ public interface OnAmbientChangedListener {
+ /**
+ * Called when an entry starts or stops pulsing.
+ * @param entry the entry that changed
+ * @param isPulsing true if the entry is now pulsing, false otherwise
+ */
+ void onAmbientStateChanged(NotificationData.Entry entry, boolean isPulsing);
+ }
+
+ private final class AmbientEntry extends AlertEntry {
+ private boolean extended;
+
+ /**
+ * Extend the lifetime of the alertEntry so that it auto-removes later. Can only be
+ * extended once.
+ */
+ private void extendPulse() {
+ if (!extended) {
+ extended = true;
+ updateEntry(false);
+ }
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ extended = false;
+ }
+
+ @Override
+ protected long calculateFinishTime() {
+ return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index d479838cdb2f..f69ad43ed79c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -321,7 +321,7 @@ public class NotificationViewHierarchyManager {
&& !row.isLowPriority()));
}
- entry.row.setShowAmbient(mPresenter.isDozing());
+ entry.row.setOnAmbient(mPresenter.isDozing());
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.row.isRemoved();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 804e8429e171..d097c8e706ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -440,6 +440,8 @@ public class NotificationData {
} else if (isHeadsUp) {
// Provide consistent ranking with headsUpManager
return mHeadsUpManager.compare(a, b);
+ } else if (a.row.isAmbientPulsing() != b.row.isAmbientPulsing()) {
+ return a.row.isAmbientPulsing() ? -1 : 1;
} else if (aMedia != bMedia) {
// Upsort current media notification.
return aMedia ? -1 : 1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index ac01fa32c902..935eaac78362 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -58,6 +58,8 @@ import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
+import com.android.systemui.statusbar.AlertingNotificationManager;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -91,7 +93,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
ExpandableNotificationRow.ExpansionLogger, NotificationUpdateHandler,
VisualStabilityManager.Callback {
private static final String TAG = "NotificationEntryMgr";
- protected static final boolean DEBUG = false;
+ protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
protected static final boolean ENABLE_HEADS_UP = true;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
@@ -121,6 +123,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
Dependency.get(ForegroundServiceController.class);
protected final NotificationListener mNotificationListener =
Dependency.get(NotificationListener.class);
+ protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
protected IStatusBarService mBarService;
protected NotificationPresenter mPresenter;
@@ -264,6 +267,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
}
mNotificationLifetimeExtenders.add(mHeadsUpManager);
+ mNotificationLifetimeExtenders.add(mAmbientPulseManager);
mNotificationLifetimeExtenders.add(mGutsManager);
mNotificationLifetimeExtenders.addAll(mRemoteInputManager.getLifetimeExtenders());
@@ -381,7 +385,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
final int userId = n.getUserId();
try {
int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- if (isHeadsUp(n.getKey())) {
+ if (mHeadsUpManager.isAlerting(n.getKey())) {
dismissalSurface = NotificationStats.DISMISSAL_PEEK;
} else if (mListContainer.hasPulsingNotifications()) {
dismissalSurface = NotificationStats.DISMISSAL_AOD;
@@ -432,12 +436,14 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
}
private void addEntry(NotificationData.Entry shadeEntry) {
- boolean isHeadsUped = shouldPeek(shadeEntry);
- if (isHeadsUped) {
+ if (shouldHeadsUp(shadeEntry)) {
mHeadsUpManager.showNotification(shadeEntry);
// Mark as seen immediately
setNotificationShown(shadeEntry.notification);
}
+ if (shouldPulse(shadeEntry)) {
+ mAmbientPulseManager.showNotification(shadeEntry);
+ }
addNotificationViews(shadeEntry);
mCallback.onNotificationAdded(shadeEntry);
}
@@ -465,7 +471,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
private void removeNotificationInternal(String key,
@Nullable NotificationListenerService.RankingMap ranking, boolean forceRemove) {
abortExistingInflation(key);
- if (mHeadsUpManager.contains(key)) {
+
+ // Attempt to remove notifications from their alert managers (heads up, ambient pulse).
+ // Though the remove itself may fail, it lets the manager know to remove as soon as
+ // possible.
+ if (mHeadsUpManager.isAlerting(key)) {
// A cancel() in response to a remote input shouldn't be delayed, as it makes the
// sending look longer than it takes.
// Also we should not defer the removal if reordering isn't allowed since otherwise
@@ -473,10 +483,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
boolean ignoreEarliestRemovalTime = mRemoteInputManager.getController().isSpinning(key)
&& !FORCE_REMOTE_INPUT_HISTORY
|| !mVisualStabilityManager.isReorderingAllowed();
-
- // Attempt to remove notification.
mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
}
+ if (mAmbientPulseManager.isAlerting(key)) {
+ mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
+ }
NotificationData.Entry entry = mNotificationData.get(key);
@@ -651,13 +662,15 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
private void addNotificationInternal(StatusBarNotification notification,
NotificationListenerService.RankingMap rankingMap) throws InflationException {
String key = notification.getKey();
- if (DEBUG) Log.d(TAG, "addNotification key=" + key);
+ if (DEBUG) {
+ Log.d(TAG, "addNotification key=" + key);
+ }
mNotificationData.updateRanking(rankingMap);
NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
rankingMap.getRanking(key, ranking);
NotificationData.Entry shadeEntry = createNotificationViews(notification, ranking);
- boolean isHeadsUped = shouldPeek(shadeEntry);
+ boolean isHeadsUped = shouldHeadsUp(shadeEntry);
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
if (shouldSuppressFullScreenIntent(shadeEntry)) {
if (DEBUG) {
@@ -750,7 +763,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
extender.setShouldManageLifetime(entry, false /* shouldManage */);
}
- Notification n = notification.getNotification();
mNotificationData.updateRanking(ranking);
final StatusBarNotification oldNotification = entry.notification;
@@ -763,10 +775,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
mForegroundServiceController.updateNotification(notification,
mNotificationData.getImportance(key));
- boolean shouldPeek = shouldPeek(entry, notification);
- boolean alertAgain = alertAgain(entry, n);
-
- updateHeadsUp(key, entry, shouldPeek, alertAgain);
+ boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
+ if (mPresenter.isDozing()) {
+ updateAlertState(entry, shouldPulse(entry), alertAgain, mAmbientPulseManager);
+ } else {
+ updateAlertState(entry, shouldHeadsUp(entry), alertAgain, mHeadsUpManager);
+ }
updateNotifications();
if (!notification.isClearable()) {
@@ -851,66 +865,147 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
}
}
- protected boolean shouldPeek(NotificationData.Entry entry) {
- return shouldPeek(entry, entry.notification);
- }
+ /**
+ * Whether the notification should peek in from the top and alert the user.
+ *
+ * @param entry the entry to check
+ * @return true if the entry should heads up, false otherwise
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+ public boolean shouldHeadsUp(NotificationData.Entry entry) {
+ StatusBarNotification sbn = entry.notification;
- public boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn) {
- if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
- if (DEBUG) Log.d(TAG, "No peeking: no huns or vr mode");
+ if (mPresenter.isDozing()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: device is dozing: " + sbn.getKey());
+ }
return false;
}
- if (mNotificationData.shouldFilterOut(entry)) {
- if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
+ if (!canAlertCommon(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: notification shouldn't alert: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: no huns or vr mode");
+ }
return false;
}
boolean inUse = mPowerManager.isScreenOn() && !mSystemServicesProxy.isDreaming();
- if (!inUse && !mPresenter.isDozing()) {
+ if (!inUse) {
if (DEBUG) {
- Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
+ Log.d(TAG, "No heads up: not in use: " + sbn.getKey());
}
return false;
}
- if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(entry)) {
- if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+ if (mNotificationData.shouldSuppressPeek(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
+ }
return false;
}
- // Peeking triggers an ambient display pulse, so disable peek is ambient is active
- if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(entry)) {
- if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+ if (isSnoozedPackage(sbn)) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey());
+ }
return false;
}
if (entry.hasJustLaunchedFullScreenIntent()) {
- if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey());
+ }
return false;
}
- if (isSnoozedPackage(sbn)) {
- if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
+ if (mNotificationData.getImportance(sbn.getKey()) < NotificationManager.IMPORTANCE_HIGH) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
+ }
return false;
}
- // Allow peeking for DEFAULT notifications only if we're on Ambient Display.
- int importanceLevel = mPresenter.isDozing() ? NotificationManager.IMPORTANCE_DEFAULT
- : NotificationManager.IMPORTANCE_HIGH;
- if (mNotificationData.getImportance(sbn.getKey()) < importanceLevel) {
- if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
+ if (!mCallback.canHeadsUp(entry, sbn)) {
return false;
}
- // Don't peek notifications that are suppressed due to group alert behavior
- if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
- if (DEBUG) Log.d(TAG, "No peeking: suppressed due to group alert behavior");
+ return true;
+ }
+
+ /**
+ * Whether or not the notification should "pulse" on the user's display when the phone is
+ * dozing. This displays the ambient view of the notification.
+ *
+ * @param entry the entry to check
+ * @return true if the entry should ambient pulse, false otherwise
+ */
+ protected boolean shouldPulse(NotificationData.Entry entry) {
+ StatusBarNotification sbn = entry.notification;
+
+ if (!mPresenter.isDozing()) {
+ if (DEBUG) {
+ Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (!canAlertCommon(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (mNotificationData.shouldSuppressAmbient(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No pulsing: ambient effect suppressed: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (mNotificationData.getImportance(sbn.getKey())
+ < NotificationManager.IMPORTANCE_DEFAULT) {
+ if (DEBUG) {
+ Log.d(TAG, "No pulsing: not important enough: " + sbn.getKey());
+ }
return false;
}
- if (!mCallback.shouldPeek(entry, sbn)) {
+ return true;
+ }
+
+ /**
+ * Common checks between heads up alerting and ambient pulse alerting. See
+ * {@link NotificationEntryManager#shouldHeadsUp(NotificationData.Entry)} and
+ * {@link NotificationEntryManager#shouldPulse(NotificationData.Entry)}. Notifications that
+ * fail any of these checks should not alert at all.
+ *
+ * @param entry the entry to check
+ * @return true if these checks pass, false if the notification should not alert
+ */
+ protected boolean canAlertCommon(NotificationData.Entry entry) {
+ StatusBarNotification sbn = entry.notification;
+
+ if (mNotificationData.shouldFilterOut(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No alerting: filtered notification: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ // Don't alert notifications that are suppressed due to group alert behavior
+ if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
+ if (DEBUG) {
+ Log.d(TAG, "No alerting: suppressed due to group alert behavior");
+ }
return false;
}
@@ -933,26 +1028,31 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
- protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldPeek,
- boolean alertAgain) {
- final boolean wasHeadsUp = isHeadsUp(key);
- if (wasHeadsUp) {
- if (!shouldPeek) {
+ /**
+ * Update the entry's alert state and call the appropriate {@link AlertingNotificationManager}
+ * method.
+ * @param entry entry to update
+ * @param shouldAlert whether or not it should be alerting
+ * @param alertAgain whether or not an alert should actually come in as if it were new
+ * @param alertManager the alerting notification manager that manages the alert state
+ */
+ private void updateAlertState(NotificationData.Entry entry, boolean shouldAlert,
+ boolean alertAgain, AlertingNotificationManager alertManager) {
+ final boolean wasAlerting = alertManager.isAlerting(entry.key);
+ if (wasAlerting) {
+ if (!shouldAlert) {
// We don't want this to be interrupting anymore, lets remove it
- mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
+ alertManager.removeNotification(entry.key,
+ false /* ignoreEarliestRemovalTime */);
} else {
- mHeadsUpManager.updateNotification(entry.key, alertAgain);
+ alertManager.updateNotification(entry.key, alertAgain);
}
- } else if (shouldPeek && alertAgain) {
- // This notification was updated to be a heads-up, show it!
- mHeadsUpManager.showNotification(entry);
+ } else if (shouldAlert && alertAgain) {
+ // This notification was updated to be alerting, show it!
+ alertManager.showNotification(entry);
}
}
- protected boolean isHeadsUp(String key) {
- return mHeadsUpManager.contains(key);
- }
-
/**
* Callback for NotificationEntryManager.
*/
@@ -1008,12 +1108,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
void onPerformRemoveNotification(StatusBarNotification statusBarNotification);
/**
- * Returns true if NotificationEntryManager should peek this notification.
+ * Returns true if NotificationEntryManager can heads up this notification.
*
- * @param entry entry of the notification that might be peeked
- * @param sbn notification that might be peeked
- * @return true if the notification should be peeked
+ * @param entry entry of the notification that might be heads upped
+ * @param sbn notification that might be heads upped
+ * @return true if the notification can be heads upped
*/
- boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn);
+ boolean canHeadsUp(NotificationData.Entry entry, StatusBarNotification sbn);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 216ed68e4fbe..019e88b11407 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -174,6 +174,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*/
private boolean mOnKeyguard;
+ /**
+ * Whether or not the row is currently on the doze screen.
+ */
+ private boolean mOnAmbient;
+
private Animator mTranslateAnim;
private ArrayList<View> mTranslateableViews;
private NotificationContentView mPublicLayout;
@@ -186,7 +191,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
private String mAppName;
+
+ /**
+ * Whether or not the notification is using the heads up view and should peek from the top.
+ */
private boolean mIsHeadsUp;
+
+ /**
+ * Whether or not the notification is using the ambient display view and is pulsing. This
+ * occurs when a high priority notification alerts while the phone is dozing or is on AOD.
+ */
+ private boolean mIsAmbientPulsing;
+
private boolean mLastChronometerRunning = true;
private ViewStub mChildrenContainerStub;
private NotificationGroupManager mGroupManager;
@@ -289,7 +305,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private float mContentTransformationAmount;
private boolean mIconsVisible = true;
private boolean mAboveShelf;
- private boolean mShowAmbient;
private boolean mIsLastChild;
private Runnable mOnDismissRunnable;
private boolean mIsLowPriority;
@@ -606,6 +621,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
+ public boolean isAmbientPulsing() {
+ return mIsAmbientPulsing;
+ }
+
+ public void setAmbientPulsing(boolean isAmbientPulsing) {
+ mIsAmbientPulsing = isAmbientPulsing;
+ }
+
public void setGroupManager(NotificationGroupManager groupManager) {
mGroupManager = groupManager;
mPrivateLayout.setGroupManager(groupManager);
@@ -1854,7 +1877,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void setDark(boolean dark, boolean fade, long delay) {
super.setDark(dark, fade, delay);
mDark = dark;
- if (!mIsHeadsUp) {
+ if (!mIsAmbientPulsing) {
// Only fade the showing view of the pulsing notification.
fade = false;
}
@@ -2155,7 +2178,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mPrivateLayout.getMinHeight();
} else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
return getMinHeight();
- } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
+ } else if (mIsSummaryWithChildren && (!mOnKeyguard || mOnAmbient)) {
return mChildrenContainer.getIntrinsicHeight();
} else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
if (isPinned() || mHeadsupDisappearRunning) {
@@ -2173,7 +2196,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private boolean isHeadsUpAllowed() {
- return !mOnKeyguard && !mShowAmbient;
+ return !mOnKeyguard && !mOnAmbient;
}
@Override
@@ -2818,11 +2841,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|| mExpandAnimationRunning || mChildIsExpanding);
}
- public void setShowAmbient(boolean showAmbient) {
- if (showAmbient != mShowAmbient) {
- mShowAmbient = showAmbient;
+ public void setOnAmbient(boolean onAmbient) {
+ if (onAmbient != mOnAmbient) {
+ mOnAmbient = onAmbient;
if (mChildrenContainer != null) {
- mChildrenContainer.notifyShowAmbientChanged();
+ mChildrenContainer.notifyDozingStateChanged();
}
notifyHeightChanged(false /* needsAnimation */);
}
@@ -2891,8 +2914,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
}
- public boolean isShowingAmbient() {
- return mShowAmbient;
+ public boolean isOnAmbient() {
+ return mOnAmbient;
}
public void setAboveShelf(boolean aboveShelf) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 0110610ca5aa..4963a0c6ae01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -725,7 +725,7 @@ public class NotificationContentView extends FrameLayout {
}
public int getMaxHeight() {
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
return getShowingAmbientView().getHeight();
} else if (mExpandedChild != null) {
return getViewHeight(VISIBLE_TYPE_EXPANDED)
@@ -752,7 +752,7 @@ public class NotificationContentView extends FrameLayout {
}
public int getMinHeight(boolean likeGroupExpanded) {
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
return getShowingAmbientView().getHeight();
} else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
return getViewHeight(VISIBLE_TYPE_CONTRACTED);
@@ -1039,7 +1039,7 @@ public class NotificationContentView extends FrameLayout {
* @return one of the static enum types in this view, calculated form the current state
*/
public int calculateVisibleType() {
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
if (mIsChildInGroup && mAmbientSingleLineChild != null) {
return VISIBLE_TYPE_AMBIENT_SINGLELINE;
} else if (mAmbientChild != null) {
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 15eaaaca2842..8969acaac532 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
@@ -20,14 +20,15 @@ import android.annotation.Nullable;
import android.content.Context;
import android.view.View;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.AmbientPulseManager;
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.NotificationData;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
@@ -44,7 +45,7 @@ public class AmbientState {
private int mSpeedBumpIndex = -1;
private boolean mDark;
private boolean mHideSensitive;
- private HeadsUpManager mHeadsUpManager;
+ private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
private float mStackTranslation;
private int mLayoutHeight;
private int mTopPadding;
@@ -207,10 +208,6 @@ public class AmbientState {
mSpeedBumpIndex = shelfIndex;
}
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
public float getStackTranslation() {
return mStackTranslation;
}
@@ -334,10 +331,10 @@ public class AmbientState {
}
public boolean isPulsing(NotificationData.Entry entry) {
- if (!mPulsing || mHeadsUpManager == null) {
+ if (!mPulsing || mAmbientPulseManager == null) {
return false;
}
- return mHeadsUpManager.getAllEntries().anyMatch(e -> (e == entry));
+ return mAmbientPulseManager.isAlerting(entry.key);
}
public boolean isPanelTracking() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 3d44e3ce6a10..da089b307850 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -213,7 +213,7 @@ public class NotificationChildrenContainer extends ViewGroup {
// calculated correctly as they are used to calculate how many we can fit on the screen.
boolean isOverflow = i == overflowIndex;
child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null &&
- !mContainingNotification.isShowingAmbient()
+ !mContainingNotification.isOnAmbient()
? mOverflowNumber.getMeasuredWidth() : 0);
child.measure(widthMeasureSpec, newHeightSpec);
// layout the divider
@@ -406,7 +406,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (childCount > maxAllowedVisibleChildren) {
int number = childCount - maxAllowedVisibleChildren;
mOverflowNumber = mHybridGroupManager.bindOverflowNumber(mOverflowNumber, number);
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
ExpandableNotificationRow overflowView = mChildren.get(0);
HybridNotificationView ambientSingleLineView = overflowView == null ? null
: overflowView.getAmbientSingleLineView();
@@ -522,7 +522,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mUserLocked) {
expandFactor = getGroupExpandFraction();
}
- boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isShowingAmbient();
+ boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isOnAmbient();
for (int i = 0; i < childCount; i++) {
if (visibleChildren >= maxAllowedVisibleChildren) {
break;
@@ -641,7 +641,7 @@ public class NotificationChildrenContainer extends ViewGroup {
getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1);
mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
mGroupOverFlowState.alpha = 0.0f;
} else if (!mChildrenExpanded) {
HybridNotificationView alignView = overflowView.getSingleLineView();
@@ -710,7 +710,7 @@ public class NotificationChildrenContainer extends ViewGroup {
@VisibleForTesting
int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
return NUMBER_OF_CHILDREN_WHEN_AMBIENT;
}
if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())
@@ -900,7 +900,7 @@ public class NotificationChildrenContainer extends ViewGroup {
return mCurrentHeader;
}
- public void notifyShowAmbientChanged() {
+ public void notifyDozingStateChanged() {
updateHeaderVisibility(false);
updateGroupOverflow();
}
@@ -970,7 +970,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private ViewGroup calculateDesiredHeader() {
ViewGroup desiredHeader;
- if (mContainingNotification.isShowingAmbient()) {
+ if (mContainingNotification.isOnAmbient()) {
desiredHeader = mNotificationHeaderAmbient;
} else if (showingAsLowPriority()) {
desiredHeader = mNotificationHeaderLowPriority;
@@ -1126,7 +1126,7 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public int getMinHeight() {
- return getMinHeight(mContainingNotification.isShowingAmbient()
+ return getMinHeight(mContainingNotification.isOnAmbient()
? NUMBER_OF_CHILDREN_WHEN_AMBIENT
: NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
}
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 da98565f9324..958a162f1c7c 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
@@ -4828,7 +4828,6 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
- mAmbientState.setHeadsUpManager(headsUpManager);
mHeadsUpManager.addListener(mRoundnessManager);
mHeadsUpManager.setAnimationStateHandler(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 0d3ba77d5079..25db4f20a450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -63,9 +63,14 @@ public class DozeScrimController {
if (!mDozing) {
return;
}
- mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
- mHandler.postDelayed(mPulseOutExtended,
- mDozeParameters.getPulseVisibleDurationExtended());
+ // All pulses except notifications should time out on their own. Pulses due to
+ // notifications should instead be managed externally based off the notification's
+ // lifetime.
+ if (mPulseReason != DozeLog.PULSE_REASON_NOTIFICATION) {
+ mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
+ mHandler.postDelayed(mPulseOutExtended,
+ mDozeParameters.getPulseVisibleDurationExtended());
+ }
mFullyPulsing = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4a059895ffe4..cfc327116303 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -177,7 +177,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
mReleaseOnExpandFinish = false;
} else {
for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
- if (contains(entry.key)) {
+ if (isAlerting(entry.key)) {
// Maybe the heads-up was removed already
removeAlertEntry(entry.key);
}
@@ -345,7 +345,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
public void onReorderingAllowed() {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
- if (contains(entry.key)) {
+ if (isAlerting(entry.key)) {
// Maybe the heads-up was removed already
removeAlertEntry(entry.key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 6b6566cc1d68..c08366a95f08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.NonNull;
import android.app.Notification;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
@@ -23,6 +24,9 @@ import androidx.annotation.Nullable;
import android.util.Log;
import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.AlertingNotificationManager;
+import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -43,15 +47,18 @@ import java.util.Objects;
/**
* A class to handle notifications and their corresponding groups.
*/
-public class NotificationGroupManager implements OnHeadsUpChangedListener {
+public class NotificationGroupManager implements OnHeadsUpChangedListener,
+ OnAmbientChangedListener {
private static final String TAG = "NotificationGroupManager";
- private static final long HEADS_UP_TRANSFER_TIMEOUT = 300;
+ private static final long ALERT_TRANSFER_TIMEOUT = 300;
private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
private OnGroupChangeListener mListener;
private int mBarState = -1;
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
private HeadsUpManager mHeadsUpManager;
+ private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+ private boolean mIsDozing;
private boolean mIsUpdatingUnchangedGroup;
private HashMap<String, NotificationData.Entry> mPendingNotifications;
@@ -162,40 +169,58 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
mListener.onGroupCreatedFromChildren(group);
}
}
- cleanUpHeadsUpStatesOnAdd(group, false /* addIsPending */);
+ cleanUpAlertStatesOnAdd(group, false /* addIsPending */);
}
public void onPendingEntryAdded(NotificationData.Entry shadeEntry) {
String groupKey = getGroupKey(shadeEntry.notification);
NotificationGroup group = mGroupMap.get(groupKey);
if (group != null) {
- cleanUpHeadsUpStatesOnAdd(group, true /* addIsPending */);
+ cleanUpAlertStatesOnAdd(group, true /* addIsPending */);
}
}
/**
- * Clean up the heads up states when a new child was added.
+ * Set whether or not the device is dozing. This allows the group manager to reset some
+ * specific alert state logic based off when the state changes.
+ * @param isDozing if the device is dozing.
+ */
+ public void setDozing(boolean isDozing) {
+ if (mIsDozing != isDozing) {
+ for (NotificationGroup group : mGroupMap.values()) {
+ group.lastAlertTransfer = 0;
+ group.alertSummaryOnNextAddition = false;
+ }
+ }
+ mIsDozing = isDozing;
+ }
+
+ /**
+ * Clean up the alert states when a new child was added.
* @param group The group where a view was added or will be added.
* @param addIsPending True if is the addition still pending or false has it already been added.
*/
- private void cleanUpHeadsUpStatesOnAdd(NotificationGroup group, boolean addIsPending) {
- if (!addIsPending && group.hunSummaryOnNextAddition) {
- if (!mHeadsUpManager.contains(group.summary.key)) {
- mHeadsUpManager.showNotification(group.summary);
+ private void cleanUpAlertStatesOnAdd(NotificationGroup group, boolean addIsPending) {
+
+ AlertingNotificationManager alertManager =
+ mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
+ if (!addIsPending && group.alertSummaryOnNextAddition) {
+ if (!alertManager.isAlerting(group.summary.key)) {
+ alertManager.showNotification(group.summary);
}
- group.hunSummaryOnNextAddition = false;
+ group.alertSummaryOnNextAddition = false;
}
// Because notification groups are not delivered as a whole unit, it may happen that a
// group child gets added quite a bit after the summary got posted. Our guidance is, that
// apps should always post the group summary as well and we'll hide it for them if the child
- // is the only child in a group. Because of this, we also have to transfer heads up to the
- // child, otherwise the invisible summary would be heads-upped.
+ // is the only child in a group. Because of this, we also have to transfer alert to the
+ // child, otherwise the invisible summary would be alerted.
// This transfer to the child is not always correct in case the app has just posted another
// child in addition to the existing one, but it hasn't arrived in systemUI yet. In such
- // a scenario we would transfer the heads up to the old child and the wrong notification
- // would be heads-upped. In oder to avoid this, we'll recover from this issue and hun the
+ // a scenario we would transfer the alert to the old child and the wrong notification
+ // would be alerted. In order to avoid this, we'll recover from this issue and alert the
// summary again instead of the old child if it's within a certain timeout.
- if (SystemClock.elapsedRealtime() - group.lastHeadsUpTransfer < HEADS_UP_TRANSFER_TIMEOUT) {
+ if (SystemClock.elapsedRealtime() - group.lastAlertTransfer < ALERT_TRANSFER_TIMEOUT) {
if (!onlySummaryAlerts(group.summary)) {
return;
}
@@ -215,26 +240,24 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
int size = children.size();
for (int i = 0; i < size; i++) {
NotificationData.Entry entry = children.get(i);
- if (onlySummaryAlerts(entry) && entry.row.isHeadsUp()) {
+ if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
releasedChild = true;
- mHeadsUpManager.removeNotification(
- entry.key, true /* releaseImmediately */);
+ alertManager.removeNotification(entry.key, true /* releaseImmediately */);
}
}
if (isolatedChild != null && onlySummaryAlerts(isolatedChild)
- && isolatedChild.row.isHeadsUp()) {
+ && alertManager.isAlerting(isolatedChild.key)) {
releasedChild = true;
- mHeadsUpManager.removeNotification(
- isolatedChild.key, true /* releaseImmediately */);
+ alertManager.removeNotification(isolatedChild.key, true /* releaseImmediately */);
}
- if (releasedChild && !mHeadsUpManager.contains(group.summary.key)) {
+ if (releasedChild && !alertManager.isAlerting(group.summary.key)) {
boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
if (notifyImmediately) {
- mHeadsUpManager.showNotification(group.summary);
+ alertManager.showNotification(group.summary);
} else {
- group.hunSummaryOnNextAddition = true;
+ group.alertSummaryOnNextAddition = true;
}
- group.lastHeadsUpTransfer = 0;
+ group.lastAlertTransfer = 0;
}
}
}
@@ -264,8 +287,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
}
private void onEntryBecomingChild(NotificationData.Entry entry) {
- if (entry.row.isHeadsUp()) {
- onHeadsUpStateChanged(entry, true);
+ if (shouldIsolate(entry)) {
+ isolateNotification(entry);
}
}
@@ -281,7 +304,11 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
&& hasIsolatedChildren(group)));
if (prevSuppressed != group.suppressed) {
if (group.suppressed) {
- handleSuppressedSummaryHeadsUpped(group.summary);
+ if (mHeadsUpManager.isAlerting(group.summary.key)) {
+ handleSuppressedSummaryAlerted(group.summary, mHeadsUpManager);
+ } else if (mAmbientPulseManager.isAlerting(group.summary.key)) {
+ handleSuppressedSummaryAlerted(group.summary, mAmbientPulseManager);
+ }
}
if (!mIsUpdatingUnchangedGroup && mListener != null) {
mListener.onGroupsChanged();
@@ -495,54 +522,56 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
}
@Override
+ public void onAmbientStateChanged(NotificationData.Entry entry, boolean isAmbient) {
+ onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
+ }
+
+ @Override
public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
+ }
+
+ private void onAlertStateChanged(NotificationData.Entry entry, boolean isAlerting,
+ AlertingNotificationManager alertManager) {
final StatusBarNotification sbn = entry.notification;
- if (entry.row.isHeadsUp()) {
- if (shouldIsolate(sbn)) {
- // We will be isolated now, so lets update the groups
- onEntryRemovedInternal(entry, entry.notification);
-
- mIsolatedEntries.put(sbn.getKey(), sbn);
-
- onEntryAdded(entry);
- // We also need to update the suppression of the old group, because this call comes
- // even before the groupManager knows about the notification at all.
- // When the notification gets added afterwards it is already isolated and therefore
- // it doesn't lead to an update.
- updateSuppression(mGroupMap.get(entry.notification.getGroupKey()));
- mListener.onGroupsChanged();
- } else {
- handleSuppressedSummaryHeadsUpped(entry);
+ if (isAlerting) {
+ if (shouldIsolate(entry)) {
+ isolateNotification(entry);
+ } else if (sbn.getNotification().isGroupSummary()
+ && isGroupSuppressed(sbn.getGroupKey())){
+ handleSuppressedSummaryAlerted(entry, alertManager);
}
} else {
- if (mIsolatedEntries.containsKey(sbn.getKey())) {
- // not isolated anymore, we need to update the groups
- onEntryRemovedInternal(entry, entry.notification);
- mIsolatedEntries.remove(sbn.getKey());
- onEntryAdded(entry);
- mListener.onGroupsChanged();
- }
+ stopIsolatingNotification(entry);
}
}
- private void handleSuppressedSummaryHeadsUpped(NotificationData.Entry entry) {
- StatusBarNotification sbn = entry.notification;
+ /**
+ * Handles the scenario where a summary that has been suppressed is alerted. A suppressed
+ * summary should for all intents and purposes be invisible to the user and as a result should
+ * not alert. When this is the case, it is our responsibility to pass the alert to the
+ * appropriate child which will be the representative notification alerting for the group.
+ * @param summary the summary that is suppressed and alerting
+ * @param alertManager the alert manager that manages the alerting summary
+ */
+ private void handleSuppressedSummaryAlerted(@NonNull NotificationData.Entry summary,
+ @NonNull AlertingNotificationManager alertManager) {
+ StatusBarNotification sbn = summary.notification;
if (!isGroupSuppressed(sbn.getGroupKey())
|| !sbn.getNotification().isGroupSummary()
- || !entry.row.isHeadsUp()) {
+ || !alertManager.isAlerting(sbn.getKey())) {
return;
}
- // The parent of a suppressed group got huned, lets hun the child!
+ // The parent of a suppressed group got alerted, lets alert the child!
NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
- if (pendingInflationsWillAddChildren(notificationGroup)) {
- // New children will actually be added to this group, let's not transfer the heads
- // up
- return;
- }
-
if (notificationGroup != null) {
+ if (pendingInflationsWillAddChildren(notificationGroup)) {
+ // New children will actually be added to this group, let's not transfer the alert.
+ return;
+ }
+
Iterator<NotificationData.Entry> iterator
= notificationGroup.children.values().iterator();
NotificationData.Entry child = iterator.hasNext() ? iterator.next() : null;
@@ -551,20 +580,35 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
}
if (child != null) {
if (child.row.keepInParent() || child.row.isRemoved() || child.row.isDismissed()) {
- // the notification is actually already removed, no need to do heads-up on it.
+ // the notification is actually already removed, no need to do alert on it.
return;
}
- if (mHeadsUpManager.contains(child.key)) {
- mHeadsUpManager.updateNotification(child.key, true /* alert */);
- } else {
- if (onlySummaryAlerts(entry)) {
- notificationGroup.lastHeadsUpTransfer = SystemClock.elapsedRealtime();
- }
- mHeadsUpManager.showNotification(child);
- }
+ transferAlertStateToChild(summary, child, alertManager);
}
}
- mHeadsUpManager.removeNotification(entry.key, true /* releaseImmediately */);
+ }
+
+ /**
+ * Transfers the alert state from a given summary notification to the specified child. The
+ * result is the child will now alert while the summary does not.
+ *
+ * @param summary the currently alerting summary notification
+ * @param child the child that should receive the alert
+ * @param alertManager the manager for the alert
+ */
+ private void transferAlertStateToChild(@NonNull NotificationData.Entry summary,
+ @NonNull NotificationData.Entry child,
+ @NonNull AlertingNotificationManager alertManager) {
+ NotificationGroup notificationGroup = mGroupMap.get(summary.notification.getGroupKey());
+ if (alertManager.isAlerting(child.key)) {
+ alertManager.updateNotification(child.key, true /* alert */);
+ } else {
+ if (onlySummaryAlerts(summary)) {
+ notificationGroup.lastAlertTransfer = SystemClock.elapsedRealtime();
+ }
+ alertManager.showNotification(child);
+ }
+ alertManager.removeNotification(summary.key, true /* releaseImmediately */);
}
private boolean onlySummaryAlerts(NotificationData.Entry entry) {
@@ -596,13 +640,69 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
return false;
}
- private boolean shouldIsolate(StatusBarNotification sbn) {
+ /**
+ * Whether a notification that is normally part of a group should be temporarily isolated from
+ * the group and put in their own group visually. This generally happens when the notification
+ * is alerting.
+ *
+ * @param entry the notification to check
+ * @return true if the entry should be isolated
+ */
+
+ private boolean shouldIsolate(NotificationData.Entry entry) {
+ StatusBarNotification sbn = entry.notification;
NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
- return (sbn.isGroup() && !sbn.getNotification().isGroupSummary())
- && (sbn.getNotification().fullScreenIntent != null
- || notificationGroup == null
- || !notificationGroup.expanded
- || isGroupNotFullyVisible(notificationGroup));
+ if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
+ return false;
+ }
+ if (!mIsDozing && !mHeadsUpManager.isAlerting(entry.key)) {
+ return false;
+ }
+ if (mIsDozing && !mAmbientPulseManager.isAlerting(entry.key)) {
+ return false;
+ }
+ return (sbn.getNotification().fullScreenIntent != null
+ || notificationGroup == null
+ || !notificationGroup.expanded
+ || isGroupNotFullyVisible(notificationGroup));
+ }
+
+ /**
+ * Isolate a notification from its group so that it visually shows as its own group.
+ *
+ * @param entry the notification to isolate
+ */
+ private void isolateNotification(NotificationData.Entry entry) {
+ StatusBarNotification sbn = entry.notification;
+
+ // We will be isolated now, so lets update the groups
+ onEntryRemovedInternal(entry, entry.notification);
+
+ mIsolatedEntries.put(sbn.getKey(), sbn);
+
+ onEntryAdded(entry);
+ // We also need to update the suppression of the old group, because this call comes
+ // even before the groupManager knows about the notification at all.
+ // When the notification gets added afterwards it is already isolated and therefore
+ // it doesn't lead to an update.
+ updateSuppression(mGroupMap.get(entry.notification.getGroupKey()));
+ mListener.onGroupsChanged();
+ }
+
+ /**
+ * Stop isolating a notification and re-group it with its original logical group.
+ *
+ * @param entry the notification to un-isolate
+ */
+ private void stopIsolatingNotification(NotificationData.Entry entry) {
+ StatusBarNotification sbn = entry.notification;
+ if (mIsolatedEntries.containsKey(sbn.getKey())) {
+ // not isolated anymore, we need to update the groups
+ onEntryRemovedInternal(entry, entry.notification);
+ mIsolatedEntries.remove(sbn.getKey());
+ onEntryAdded(entry);
+ mListener.onGroupsChanged();
+ }
}
private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) {
@@ -641,11 +741,11 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener {
*/
public boolean suppressed;
/**
- * The time when the last heads transfer from group to child happened, while the summary
- * has the flags to heads up on its own.
+ * The time when the last alert transfer from group to child happened, while the summary
+ * has the flags to alert up on its own.
*/
- public long lastHeadsUpTransfer;
- public boolean hunSummaryOnNextAddition;
+ public long lastAlertTransfer;
+ public boolean alertSummaryOnNextAddition;
@Override
public String toString() {
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 759e8ea90761..e1d86387cdfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -187,6 +187,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.AppOpsListener;
import com.android.systemui.statusbar.BackDropView;
@@ -254,7 +255,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ActivityStarter, OnUnlockMethodChangedListener,
OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter,
- StatusBarStateController.StateListener {
+ StatusBarStateController.StateListener, AmbientPulseManager.OnAmbientChangedListener {
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -865,6 +866,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mHeadsUpManager.addListener(mNotificationPanel);
mHeadsUpManager.addListener(mGroupManager);
mHeadsUpManager.addListener(mVisualStabilityManager);
+ mAmbientPulseManager.addListener(this);
+ mAmbientPulseManager.addListener(mGroupManager);
mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
putComponent(HeadsUpManager.class, mHeadsUpManager);
@@ -1233,7 +1236,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onPerformRemoveNotification(StatusBarNotification n) {
if (mNotificationPanel.hasPulsingNotifications() &&
- !mHeadsUpManager.hasNotifications()) {
+ !mAmbientPulseManager.hasNotifications()) {
// We were showing a pulse for a notification, but no notifications are pulsing anymore.
// Finish the pulse.
mDozeScrimController.pulseOutNow();
@@ -1697,8 +1700,12 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
- public boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
- if (mIsOccluded && !isDozing()) {
+ public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+ if (isDozing()) {
+ return false;
+ }
+
+ if (mIsOccluded) {
boolean devicePublic = mLockscreenUserManager.
isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
boolean userPublic = devicePublic
@@ -1711,17 +1718,14 @@ public class StatusBar extends SystemUI implements DemoMode,
if (!panelsEnabled()) {
if (DEBUG) {
- Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey());
+ Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
}
return false;
}
if (sbn.getNotification().fullScreenIntent != null) {
if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
- return false;
- } else if (isDozing()) {
- // We never want heads up when we are dozing.
+ if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
return false;
} else {
// we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
@@ -1797,9 +1801,16 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
mEntryManager.updateNotificationRanking(null /* rankingMap */);
+ }
- if (isHeadsUp) {
- mDozeServiceHost.fireNotificationHeadsUp();
+ @Override
+ public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+ mEntryManager.updateNotificationRanking(null);
+ if (isAmbient) {
+ mDozeServiceHost.fireNotificationPulse();
+ } else if (!mAmbientPulseManager.hasNotifications()) {
+ // There are no longer any notifications to show. We should end the pulse now.
+ mDozeScrimController.pulseOutNow();
}
}
@@ -3603,6 +3614,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardIndicationController.setDozing(mDozing);
mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation);
mNotificationLogger.setDozing(mDozing);
+ mGroupManager.setDozing(mDozing);
updateQsExpansionEnabled();
Trace.endSection();
}
@@ -4149,6 +4161,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onStartedWakingUp() {
mDeviceInteractive = true;
+ mAmbientPulseManager.releaseAllImmediately();
mVisualStabilityManager.setScreenOn(true);
mNotificationPanel.setTouchAndAnimationDisabled(false);
mDozeServiceHost.stopDozing();
@@ -4181,11 +4194,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public void onScreenTurnedOff() {
mFalsingManager.onScreenOff();
mScrimController.onScreenTurnedOff();
- // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
- // in that case destroys the HeadsUpManager state, so don't do it in that case.
- if (!isPulsing()) {
- updateIsKeyguard();
- }
+ updateIsKeyguard();
}
};
@@ -4424,9 +4433,9 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- public void fireNotificationHeadsUp() {
+ public void fireNotificationPulse() {
for (Callback callback : mCallbacks) {
- callback.onNotificationHeadsUp();
+ callback.onNotificationAlerted();
}
}
@@ -4462,7 +4471,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onPulseStarted() {
callback.onPulseStarted();
- if (mHeadsUpManager.hasNotifications()) {
+ if (mAmbientPulseManager.hasNotifications()) {
// Only pulse the stack scroller if there's actually something to show.
// Otherwise just show the always-on screen.
setPulsing(true);
@@ -4543,7 +4552,11 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void extendPulse() {
- mDozeScrimController.extendPulse();
+ if (mDozeScrimController.isPulsing() && mAmbientPulseManager.hasNotifications()) {
+ mAmbientPulseManager.extendPulse();
+ } else {
+ mDozeScrimController.extendPulse();
+ }
}
@Override
@@ -4629,6 +4642,8 @@ public class StatusBar extends SystemUI implements DemoMode,
// for heads up notifications
protected HeadsUpManagerPhone mHeadsUpManager;
+ protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+
private AboveShelfObserver mAboveShelfObserver;
// handling reordering
@@ -4734,7 +4749,7 @@ public class StatusBar extends SystemUI implements DemoMode,
final boolean wasOccluded = mIsOccluded;
dismissKeyguardThenExecute(() -> {
// TODO: Some of this code may be able to move to NotificationEntryManager.
- if (mHeadsUpManager != null && mHeadsUpManager.contains(notificationKey)) {
+ if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
// Release the HUN notification to the shade.
if (isPresenterFullyCollapsed()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index e8389af85f22..3db1456446a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -460,6 +460,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean staying = mStatusBar.hideKeyguard();
if (!staying) {
mStatusBarWindowController.setKeyguardFadingAway(true);
+ // hide() will happen asynchronously and might arrive after the scrims
+ // were already hidden, this means that the transition callback won't
+ // be triggered anymore and StatusBarWindowController will be forever in
+ // the fadingAway state.
+ mStatusBar.updateScrimController();
wakeAndUnlockDejank();
} else {
mStatusBar.finishKeyguardFadingAway();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 52b813f5388b..7dd0d0fbef47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -586,7 +586,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
if (mShowImeOnInputConnection && inputConnection != null) {
- final InputMethodManager imm = InputMethodManager.getInstance();
+ final InputMethodManager imm =
+ getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
// onCreateInputConnection is called by InputMethodManager in the middle of
// setting up the connection to the IME; wait with requesting the IME until that
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index c2da7f5280b5..5c8336c8dee1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -88,14 +88,14 @@ public class DozeTriggersTest extends SysuiTestCase {
mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
- mHost.callback.onNotificationHeadsUp();
+ mHost.callback.onNotificationAlerted();
mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
verify(mMachine, never()).requestState(any());
verify(mMachine, never()).requestPulse(anyInt());
- mHost.callback.onNotificationHeadsUp();
+ mHost.callback.onNotificationAlerted();
mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index f21ce2780d40..8b41516044f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -56,19 +56,19 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
- private static final int TEST_MINIMUM_DISPLAY_TIME = 200;
- private static final int TEST_AUTO_DISMISS_TIME = 500;
+ protected static final int TEST_MINIMUM_DISPLAY_TIME = 200;
+ protected static final int TEST_AUTO_DISMISS_TIME = 500;
// Number of notifications to use in tests requiring multiple notifications
private static final int TEST_NUM_NOTIFICATIONS = 4;
- private static final int TEST_TIMEOUT_TIME = 10000;
- private final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
+ protected static final int TEST_TIMEOUT_TIME = 10000;
+ protected final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
private AlertingNotificationManager mAlertingNotificationManager;
protected NotificationData.Entry mEntry;
protected Handler mTestHandler;
private StatusBarNotification mSbn;
- private boolean mTimedOut = false;
+ protected boolean mTimedOut = false;
@Mock protected ExpandableNotificationRow mRow;
@@ -122,7 +122,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
public void testShowNotification_addsEntry() {
mAlertingNotificationManager.showNotification(mEntry);
- assertTrue(mAlertingNotificationManager.contains(mEntry.key));
+ assertTrue(mAlertingNotificationManager.isAlerting(mEntry.key));
assertTrue(mAlertingNotificationManager.hasNotifications());
assertEquals(mEntry, mAlertingNotificationManager.getEntry(mEntry.key));
}
@@ -136,7 +136,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
TestableLooper.get(this).processMessages(1);
assertFalse("Test timed out", mTimedOut);
- assertFalse(mAlertingNotificationManager.contains(mEntry.key));
+ assertFalse(mAlertingNotificationManager.isAlerting(mEntry.key));
}
@Test
@@ -146,7 +146,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
// Try to remove but defer, since the notification has not been shown long enough.
mAlertingNotificationManager.removeNotification(mEntry.key, false /* releaseImmediately */);
- assertTrue(mAlertingNotificationManager.contains(mEntry.key));
+ assertTrue(mAlertingNotificationManager.isAlerting(mEntry.key));
}
@Test
@@ -156,7 +156,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
// Remove forcibly with releaseImmediately = true.
mAlertingNotificationManager.removeNotification(mEntry.key, true /* releaseImmediately */);
- assertFalse(mAlertingNotificationManager.contains(mEntry.key));
+ assertFalse(mAlertingNotificationManager.isAlerting(mEntry.key));
}
@Test
@@ -174,10 +174,18 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
}
@Test
- public void testShouldExtendLifetime_notShownLongEnough() {
+ public void testCanRemoveImmediately_notShownLongEnough() {
mAlertingNotificationManager.showNotification(mEntry);
- // The entry has just been added so the lifetime should be extended
+ // The entry has just been added so we should not remove immediately.
+ assertFalse(mAlertingNotificationManager.canRemoveImmediately(mEntry.key));
+ }
+
+ @Test
+ public void testShouldExtendLifetime() {
+ mAlertingNotificationManager.showNotification(mEntry);
+
+ // While the entry is alerting, it should not be removable.
assertTrue(mAlertingNotificationManager.shouldExtendLifetime(mEntry));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java
new file mode 100644
index 000000000000..f0344e6936e7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AmbientPulseManagerTest extends AlertingNotificationManagerTest {
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ private static final int TEST_EXTENSION_TIME = 500;
+ private AmbientPulseManager mAmbientPulseManager;
+ private boolean mLivesPastNormalTime;
+
+ protected AlertingNotificationManager createAlertingNotificationManager() {
+ return mAmbientPulseManager;
+ }
+
+ @Before
+ public void setUp() {
+ mAmbientPulseManager = new AmbientPulseManager(mContext);
+ mAmbientPulseManager.mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+ mAmbientPulseManager.mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+ mAmbientPulseManager.mExtensionTime = TEST_EXTENSION_TIME;
+ super.setUp();
+ mAmbientPulseManager.mHandler = mTestHandler;
+ }
+
+ @Test
+ public void testExtendPulse() {
+ mAmbientPulseManager.showNotification(mEntry);
+ Runnable pastNormalTimeRunnable =
+ () -> mLivesPastNormalTime = mAmbientPulseManager.isAlerting(mEntry.key);
+ mTestHandler.postDelayed(pastNormalTimeRunnable,
+ mAmbientPulseManager.mAutoDismissNotificationDecay +
+ mAmbientPulseManager.mExtensionTime / 2);
+ mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
+
+ mAmbientPulseManager.extendPulse();
+
+ // Wait for normal time runnable and extended remove runnable and process them on arrival.
+ TestableLooper.get(this).processMessages(2);
+
+ assertFalse("Test timed out", mTimedOut);
+ assertTrue("Pulse was not extended", mLivesPastNormalTime);
+ assertFalse(mAmbientPulseManager.isAlerting(mEntry.key));
+ }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index b2170fa3cb95..edf29ac1c4f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -31,6 +31,7 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.NotificationInflaterTest;
@@ -63,6 +64,7 @@ public class NotificationTestHelper {
mContext = context;
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null);
+ mGroupManager.setHeadsUpManager(mHeadsUpManager);
}
public ExpandableNotificationRow createRow() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 087aa5953d90..272845396e27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.stack;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.NotificationHeaderView;
@@ -51,7 +50,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
@Test
public void testGetMaxAllowedVisibleChildren_ambient() {
- mGroup.setShowAmbient(true);
+ mGroup.setOnAmbient(true);
Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_AMBIENT);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index a81d17f12de1..10707957521e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -82,28 +82,26 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
// Remove should succeed because the notification is swiped out
mHeadsUpManager.removeNotification(mEntry.key, false /* releaseImmediately */);
- assertFalse(mHeadsUpManager.contains(mEntry.key));
+ assertFalse(mHeadsUpManager.isAlerting(mEntry.key));
}
@Test
- public void testShouldExtendLifetime_swipedOut() {
+ public void testCanRemoveImmediately_swipedOut() {
mHeadsUpManager.showNotification(mEntry);
mHeadsUpManager.addSwipedOutNotification(mEntry.key);
- // Notification is swiped so its lifetime should not be extended even if it hasn't been
- // shown long enough
- assertFalse(mHeadsUpManager.shouldExtendLifetime(mEntry));
+ // Notification is swiped so it can be immediately removed.
+ assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.key));
}
@Test
- public void testShouldExtendLifetime_notTopEntry() {
+ public void testCanRemoveImmediately_notTopEntry() {
NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1));
laterEntry.row = mRow;
mHeadsUpManager.showNotification(mEntry);
mHeadsUpManager.showNotification(laterEntry);
- // Notification is "behind" a higher priority notification so we have no reason to keep
- // its lifetime extended
- assertFalse(mHeadsUpManager.shouldExtendLifetime(mEntry));
+ // Notification is "behind" a higher priority notification so we can remove it immediately.
+ assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.key));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
index 6a3c8a850831..464f74b3aa36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -36,6 +36,7 @@ import android.testing.TestableLooper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
@@ -60,15 +61,23 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
private static final String TEST_CHANNEL_ID = "test_channel";
private static final String TEST_GROUP_ID = "test_group";
private static final String TEST_PACKAGE_NAME = "test_pkg";
- private NotificationGroupManager mGroupManager = new NotificationGroupManager();
+ private NotificationGroupManager mGroupManager;
private int mId = 0;
@Mock HeadsUpManager mHeadsUpManager;
+ @Mock AmbientPulseManager mAmbientPulseManager;
@Before
public void setup() {
- mGroupManager.setHeadsUpManager(mHeadsUpManager);
- mGroupManager.setOnGroupChangeListener(mock(OnGroupChangeListener.class));
+ mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
+
+ initializeGroupManager();
+ }
+
+ private void initializeGroupManager() {
+ mGroupManager = new NotificationGroupManager();
+ mGroupManager.setHeadsUpManager(mHeadsUpManager);
+ mGroupManager.setOnGroupChangeListener(mock(OnGroupChangeListener.class));
}
@Test
@@ -141,8 +150,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(createChildNotification());
- when(childEntry.row.isHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.contains(childEntry.key)).thenReturn(true);
+ when(mHeadsUpManager.isAlerting(childEntry.key)).thenReturn(true);
mGroupManager.onHeadsUpStateChanged(childEntry, true);
@@ -154,17 +162,35 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
}
@Test
+ public void testAmbientPulseEntryIsIsolated() {
+ mGroupManager.setDozing(true);
+ NotificationData.Entry childEntry = createChildNotification();
+ NotificationData.Entry summaryEntry = createSummaryNotification();
+ mGroupManager.onEntryAdded(summaryEntry);
+ mGroupManager.onEntryAdded(childEntry);
+ mGroupManager.onEntryAdded(createChildNotification());
+ when(mAmbientPulseManager.isAlerting(childEntry.key)).thenReturn(true);
+
+ mGroupManager.onAmbientStateChanged(childEntry, true);
+
+ // Child entries that are heads upped should be considered separate groups visually even if
+ // they are the same group logically
+ assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification));
+ assertEquals(summaryEntry.row,
+ mGroupManager.getLogicalGroupSummary(childEntry.notification));
+ }
+
+ @Test
public void testSuppressedSummaryHeadsUpTransfersToChild() {
NotificationData.Entry summaryEntry = createSummaryNotification();
- when(summaryEntry.row.isHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.contains(summaryEntry.key)).thenReturn(true);
+ when(mHeadsUpManager.isAlerting(summaryEntry.key)).thenReturn(true);
NotificationData.Entry childEntry = createChildNotification();
- // Summary will be suppressed because there is only one child
+ // Summary will be suppressed because there is only one child.
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
- // A suppressed summary should transfer its heads up state to the child
+ // A suppressed summary should transfer its heads up state to the child.
verify(mHeadsUpManager, never()).showNotification(summaryEntry);
verify(mHeadsUpManager).showNotification(childEntry);
}
@@ -175,24 +201,64 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.setHeadsUpManager(mHeadsUpManager);
NotificationData.Entry summaryEntry =
createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- when(summaryEntry.row.isHeadsUp()).thenReturn(true);
NotificationData.Entry childEntry =
createChildNotification(Notification.GROUP_ALERT_SUMMARY);
NotificationData.Entry childEntry2 =
createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+ mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of heads up state from summary to child.
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
- when(summaryEntry.row.isHeadsUp()).thenReturn(false);
- when(childEntry.row.isHeadsUp()).thenReturn(true);
// Add second child notification so that summary is no longer suppressed.
mGroupManager.onEntryAdded(childEntry2);
// The heads up state should transfer back to the summary as there is now more than one
// child and the summary should no longer be suppressed.
- assertTrue(mHeadsUpManager.contains(summaryEntry.key));
- assertFalse(mHeadsUpManager.contains(childEntry.key));
+ assertTrue(mHeadsUpManager.isAlerting(summaryEntry.key));
+ assertFalse(mHeadsUpManager.isAlerting(childEntry.key));
+ }
+
+ @Test
+ public void testSuppressedSummaryAmbientPulseTransfersToChild() {
+ mGroupManager.setDozing(true);
+ NotificationData.Entry summaryEntry = createSummaryNotification();
+ when(mAmbientPulseManager.isAlerting(summaryEntry.key)).thenReturn(true);
+ NotificationData.Entry childEntry = createChildNotification();
+
+ // Summary will be suppressed because there is only one child.
+ mGroupManager.onEntryAdded(summaryEntry);
+ mGroupManager.onEntryAdded(childEntry);
+
+ // A suppressed summary should transfer its ambient state to the child.
+ verify(mAmbientPulseManager, never()).showNotification(summaryEntry);
+ verify(mAmbientPulseManager).showNotification(childEntry);
+ }
+
+ @Test
+ public void testSuppressedSummaryAmbientPulseTransfersToChildButBackAgain() {
+ mGroupManager.setDozing(true);
+ mAmbientPulseManager = new AmbientPulseManager(mContext);
+ mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
+ initializeGroupManager();
+ NotificationData.Entry summaryEntry =
+ createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
+ NotificationData.Entry childEntry =
+ createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+ NotificationData.Entry childEntry2 =
+ createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+ mAmbientPulseManager.showNotification(summaryEntry);
+ // Trigger a transfer of ambient state from summary to child.
+ mGroupManager.onEntryAdded(summaryEntry);
+ mGroupManager.onEntryAdded(childEntry);
+
+ // Add second child notification so that summary is no longer suppressed.
+ mGroupManager.onEntryAdded(childEntry2);
+
+ // The ambient state should transfer back to the summary as there is now more than one
+ // child and the summary should no longer be suppressed.
+ assertTrue(mAmbientPulseManager.isAlerting(summaryEntry.key));
+ assertFalse(mAmbientPulseManager.isAlerting(childEntry.key));
}
private NotificationData.Entry createSummaryNotification() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index cbba251c8895..5006b0b29b0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -358,7 +358,7 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
- public void testShouldPeek_nonSuppressedGroupSummary() {
+ public void testShouldHeadsUp_nonSuppressedGroupSummary() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
@@ -375,11 +375,11 @@ public class StatusBarTest extends SysuiTestCase {
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertTrue(mEntryManager.shouldPeek(entry, sbn));
+ assertTrue(mEntryManager.shouldHeadsUp(entry));
}
@Test
- public void testShouldPeek_suppressedGroupSummary() {
+ public void testShouldHeadsUp_suppressedGroupSummary() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
@@ -396,11 +396,11 @@ public class StatusBarTest extends SysuiTestCase {
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertFalse(mEntryManager.shouldPeek(entry, sbn));
+ assertFalse(mEntryManager.shouldHeadsUp(entry));
}
@Test
- public void testShouldPeek_suppressedPeek() {
+ public void testShouldHeadsUp_suppressedHeadsUp() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
@@ -414,11 +414,11 @@ public class StatusBarTest extends SysuiTestCase {
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertFalse(mEntryManager.shouldPeek(entry, sbn));
+ assertFalse(mEntryManager.shouldHeadsUp(entry));
}
@Test
- public void testShouldPeek_noSuppressedPeek() {
+ public void testShouldHeadsUp_noSuppressedHeadsUp() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
@@ -432,31 +432,31 @@ public class StatusBarTest extends SysuiTestCase {
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertTrue(mEntryManager.shouldPeek(entry, sbn));
+ assertTrue(mEntryManager.shouldHeadsUp(entry));
}
@Test
- public void testPeek_disabledStatusBar() {
+ public void testHeadsUp_disabledStatusBar() {
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
mStatusBar.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
- assertFalse("The panel shouldn't allow peek while disabled",
- mStatusBar.shouldPeek(entry, sbn));
+ assertFalse("The panel shouldn't allow heads up while disabled",
+ mStatusBar.canHeadsUp(entry, sbn));
}
@Test
- public void testPeek_disabledNotificationShade() {
+ public void testHeadsUp_disabledNotificationShade() {
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
mStatusBar.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
- assertFalse("The panel shouldn't allow peek while notitifcation shade disabled",
- mStatusBar.shouldPeek(entry, sbn));
+ assertFalse("The panel shouldn't allow heads up while notification shade disabled",
+ mStatusBar.canHeadsUp(entry, sbn));
}
@Test
@@ -472,7 +472,7 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
- public void testPanelOpenForPeek() {
+ public void testPanelOpenForHeadsUp() {
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
when(mNotificationList.size()).thenReturn(5);
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index ee01d8633ae7..4f0e17055769 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -93,10 +93,12 @@ public class LooperStatsService extends Binder {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
List<LooperStats.ExportedEntry> entries = mStats.getEntries();
entries.sort(Comparator
- .comparing((LooperStats.ExportedEntry entry) -> entry.threadName)
+ .comparing((LooperStats.ExportedEntry entry) -> entry.workSourceUid)
+ .thenComparing(entry -> entry.threadName)
.thenComparing(entry -> entry.handlerClassName)
.thenComparing(entry -> entry.messageName));
String header = String.join(",", Arrays.asList(
+ "work_source_uid",
"thread_name",
"handler_class",
"message_name",
@@ -110,11 +112,11 @@ public class LooperStatsService extends Binder {
"exception_count"));
pw.println(header);
for (LooperStats.ExportedEntry entry : entries) {
- pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.threadName,
- entry.handlerClassName, entry.messageName, entry.isInteractive,
- entry.messageCount, entry.recordedMessageCount, entry.totalLatencyMicros,
- entry.maxLatencyMicros, entry.cpuUsageMicros, entry.maxCpuUsageMicros,
- entry.exceptionCount);
+ pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.workSourceUid,
+ entry.threadName, entry.handlerClassName, entry.messageName,
+ entry.isInteractive, entry.messageCount, entry.recordedMessageCount,
+ entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros,
+ entry.maxCpuUsageMicros, entry.exceptionCount);
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e5aa3f41857c..510d333355a3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2490,7 +2490,7 @@ public final class ActiveServices {
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
- mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
+ mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b898a90dbb55..f7fe9e2455f1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -665,11 +665,6 @@ public class ActivityManagerService extends IActivityManager.Stub
int mNextIsolatedProcessUid = 0;
/**
- * The currently running heavy-weight process, if any.
- */
- ProcessRecord mHeavyWeightProcess = null;
-
- /**
* Non-persistent appId whitelist for background restrictions
*/
int[] mBackgroundAppIdWhitelist = new int[] {
@@ -826,12 +821,6 @@ public class ActivityManagerService extends IActivityManager.Stub
final SparseArray<UidRecord> mValidateUids = new SparseArray<>();
/**
- * Packages that the user has asked to have run in screen size
- * compatibility mode instead of filling the screen.
- */
- final CompatModePackages mCompatModePackages;
-
- /**
* Set of IntentSenderRecord objects that are currently active.
*/
final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
@@ -1097,11 +1086,10 @@ public class ActivityManagerService extends IActivityManager.Stub
volatile boolean mSystemReady = false;
volatile boolean mOnBattery = false;
volatile int mFactoryTest;
+ volatile boolean mBooting = false;
- @GuardedBy("this") boolean mBooting = false;
@GuardedBy("this") boolean mCallFinishBooting = false;
@GuardedBy("this") boolean mBootAnimationComplete = false;
- @GuardedBy("this") boolean mLaunchWarningShown = false;
private @GuardedBy("this") boolean mCheckedForSetup = false;
final Context mContext;
@@ -1388,10 +1376,8 @@ public class ActivityManagerService extends IActivityManager.Stub
long mLastWriteTime = 0;
- /**
- * Set to true after the system has finished booting.
- */
- boolean mBooted = false;
+ /** Set to true after the system has finished booting. */
+ volatile boolean mBooted = false;
/**
* Current boot phase.
@@ -1441,8 +1427,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int PROC_START_TIMEOUT_MSG = 20;
static final int KILL_APPLICATION_MSG = 22;
static final int FINALIZE_PENDING_INTENT_MSG = 23;
- static final int POST_HEAVY_NOTIFICATION_MSG = 24;
- static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26;
static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27;
static final int CLEAR_DNS_CACHE_MSG = 28;
@@ -1451,7 +1435,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
static final int REPORT_MEM_USAGE_MSG = 33;
static final int UPDATE_TIME_PREFERENCE_MSG = 41;
- static final int FINISH_BOOTING_MSG = 45;
static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49;
static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50;
@@ -1758,65 +1741,6 @@ public class ActivityManagerService extends IActivityManager.Stub
case FINALIZE_PENDING_INTENT_MSG: {
((PendingIntentRecord)msg.obj).completeFinalize();
} break;
- case POST_HEAVY_NOTIFICATION_MSG: {
- INotificationManager inm = NotificationManager.getService();
- if (inm == null) {
- return;
- }
-
- ActivityRecord root = (ActivityRecord)msg.obj;
- final WindowProcessController process = root.app;
- if (process == null) {
- return;
- }
-
- try {
- Context context = mContext.createPackageContext(process.mInfo.packageName, 0);
- String text = mContext.getString(R.string.heavy_weight_notification,
- context.getApplicationInfo().loadLabel(context.getPackageManager()));
- Notification notification =
- new Notification.Builder(context,
- SystemNotificationChannels.HEAVY_WEIGHT_APP)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setWhen(0)
- .setOngoing(true)
- .setTicker(text)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(text)
- .setContentText(
- mContext.getText(R.string.heavy_weight_notification_detail))
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
- root.intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
- new UserHandle(root.userId)))
- .build();
- try {
- inm.enqueueNotificationWithTag("android", "android", null,
- SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION,
- notification, root.userId);
- } catch (RuntimeException e) {
- Slog.w(ActivityManagerService.TAG,
- "Error showing notification for heavy-weight app", e);
- } catch (RemoteException e) {
- }
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Unable to create context for heavy notification", e);
- }
- } break;
- case CANCEL_HEAVY_NOTIFICATION_MSG: {
- INotificationManager inm = NotificationManager.getService();
- if (inm == null) {
- return;
- }
- try {
- inm.cancelNotificationWithTag("android", null,
- SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1);
- } catch (RuntimeException e) {
- Slog.w(ActivityManagerService.TAG,
- "Error canceling notification for service", e);
- } catch (RemoteException e) {
- }
- } break;
case CHECK_EXCESSIVE_POWER_USE_MSG: {
synchronized (ActivityManagerService.this) {
checkExcessivePowerUsageLocked();
@@ -1853,17 +1777,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
break;
}
- case FINISH_BOOTING_MSG: {
- if (msg.arg1 != 0) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
- finishBooting();
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
- if (msg.arg2 != 0) {
- mAtmInternal.enableScreenAfterBoot(mBooted);
- }
- break;
- }
case SEND_LOCALE_TO_MOUNT_DAEMON_MSG: {
try {
Locale l = (Locale) msg.obj;
@@ -2430,7 +2343,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppErrors = null;
mAppOpsService = mInjector.getAppOpsService(null, null);
mBatteryStatsService = null;
- mCompatModePackages = null;
mConstants = null;
mHandler = null;
mHandlerThread = null;
@@ -2519,7 +2431,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
- mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mActivityTaskManager = atm;
@@ -3791,31 +3702,31 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
}
- void updateUsageStats(ActivityRecord component, boolean resumed) {
+ void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
- "updateUsageStats: comp=" + component + "res=" + resumed);
+ "updateUsageStats: comp=" + activity + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
- component.app.mUid, component.realActivity.getPackageName(),
- component.realActivity.getShortClassName(), resumed ?
+ uid, activity.getPackageName(),
+ activity.getShortClassName(), resumed ?
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
if (resumed) {
if (mUsageStatsService != null) {
- mUsageStatsService.reportEvent(component.realActivity, component.userId,
+ mUsageStatsService.reportEvent(activity, userId,
UsageEvents.Event.MOVE_TO_FOREGROUND);
}
synchronized (stats) {
- stats.noteActivityResumedLocked(component.app.mUid);
+ stats.noteActivityResumedLocked(uid);
}
} else {
if (mUsageStatsService != null) {
- mUsageStatsService.reportEvent(component.realActivity, component.userId,
+ mUsageStatsService.reportEvent(activity, userId,
UsageEvents.Event.MOVE_TO_BACKGROUND);
}
synchronized (stats) {
- stats.noteActivityPausedLocked(component.app.mUid);
+ stats.noteActivityPausedLocked(uid);
}
}
}
@@ -3895,8 +3806,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mCheckedForSetup = checked;
}
- CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
- return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
+ CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
+ return mAtmInternal.compatibilityInfoForPackage(ai);
}
private void enforceNotIsolatedCaller(String caller) {
@@ -3906,37 +3817,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public int getPackageScreenCompatMode(String packageName) {
- enforceNotIsolatedCaller("getPackageScreenCompatMode");
- synchronized (this) {
- return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
- }
- }
-
- @Override
public void setPackageScreenCompatMode(String packageName, int mode) {
- enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
- "setPackageScreenCompatMode");
- synchronized (this) {
- mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
- }
- }
-
- @Override
- public boolean getPackageAskScreenCompat(String packageName) {
- enforceNotIsolatedCaller("getPackageAskScreenCompat");
- synchronized (this) {
- return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
- }
- }
-
- @Override
- public void setPackageAskScreenCompat(String packageName, boolean ask) {
- enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
- "setPackageAskScreenCompat");
- synchronized (this) {
- mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
- }
+ mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
}
private boolean hasUsageStatsPermission(String callingPackage) {
@@ -4307,19 +4189,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
-
- synchronized(this) {
- final ProcessRecord proc = mHeavyWeightProcess;
- if (proc == null) {
- return;
- }
-
- proc.getWindowProcessController().finishActivities();
-
- mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
- proc.userId, 0));
- mHeavyWeightProcess = null;
- }
+ mAtmInternal.finishHeavyWeightApp();
}
@Override
@@ -5789,11 +5659,8 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
removeProcessNameLocked(name, uid);
- if (mHeavyWeightProcess == app) {
- mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
- mHeavyWeightProcess.userId, 0));
- mHeavyWeightProcess = null;
- }
+ mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
+
boolean needRestart = false;
if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
int pid = app.pid;
@@ -5851,11 +5718,7 @@ public class ActivityManagerService extends IActivityManager.Stub
EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
pid, app.uid, app.processName);
removeProcessNameLocked(app.processName, app.uid);
- if (mHeavyWeightProcess == app) {
- mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
- mHeavyWeightProcess.userId, 0));
- mHeavyWeightProcess = null;
- }
+ mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
// Take care of any launching providers waiting for this process.
cleanupAppInLaunchingProvidersLocked(app, true);
@@ -6034,7 +5897,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
+ processName + " with config " + getGlobalConfiguration());
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
- app.compat = compatibilityInfoForPackageLocked(appInfo);
+ app.compat = compatibilityInfoForPackage(appInfo);
ProfilerInfo profilerInfo = null;
String preBindAgent = null;
@@ -6231,7 +6094,7 @@ public class ActivityManagerService extends IActivityManager.Stub
PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
try {
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
- compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
+ compatibilityInfoForPackage(mBackupTarget.appInfo),
mBackupTarget.backupMode);
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
@@ -6264,11 +6127,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- void postFinishBooting(boolean finishBooting, boolean enableScreen) {
- mHandler.sendMessage(mHandler.obtainMessage(FINISH_BOOTING_MSG,
- finishBooting ? 1 : 0, enableScreen ? 1 : 0));
- }
-
@Override
public void showBootMessage(final CharSequence msg, final boolean always) {
if (Binder.getCallingUid() != myUid()) {
@@ -6278,6 +6136,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final void finishBooting() {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
+
synchronized (this) {
if (!mBootAnimationComplete) {
mCallFinishBooting = true;
@@ -6383,6 +6243,8 @@ public class ActivityManagerService extends IActivityManager.Stub
});
mUserController.scheduleStartProfiles();
}
+
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@Override
@@ -6393,9 +6255,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mBootAnimationComplete = true;
}
if (callFinishBooting) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
finishBooting();
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -6410,9 +6270,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (booting) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
finishBooting();
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
if (enableScreen) {
@@ -10852,7 +10710,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int clientTargetSdk) {
outInfo.pid = app.pid;
outInfo.uid = app.info.uid;
- if (mHeavyWeightProcess == app) {
+ if (mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
}
if (app.isPersistent()) {
@@ -11895,13 +11753,13 @@ public class ActivityManagerService extends IActivityManager.Stub
TimeUtils.formatDuration(mActivityTaskManager.mPreviousProcessVisibleTime, sb);
pw.println(sb);
}
- if (mHeavyWeightProcess != null && (dumpPackage == null
- || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
+ if (mActivityTaskManager.mHeavyWeightProcess != null && (dumpPackage == null
+ || mActivityTaskManager.mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
if (needSep) {
pw.println();
needSep = false;
}
- pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
+ pw.println(" mHeavyWeightProcess: " + mActivityTaskManager.mHeavyWeightProcess);
}
if (dumpAll && mPendingStarts.size() > 0) {
if (needSep) pw.println();
@@ -11920,10 +11778,10 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" mConfigWillChange: "
+ mActivityTaskManager.getTopDisplayFocusedStack().mConfigWillChange);
}
- if (mCompatModePackages.getPackages().size() > 0) {
+ if (mActivityTaskManager.mCompatModePackages.getPackages().size() > 0) {
boolean printed = false;
for (Map.Entry<String, Integer> entry
- : mCompatModePackages.getPackages().entrySet()) {
+ : mActivityTaskManager.mCompatModePackages.getPackages().entrySet()) {
String pkg = entry.getKey();
int mode = entry.getValue();
if (dumpPackage != null && !dumpPackage.equals(pkg)) {
@@ -12305,12 +12163,13 @@ public class ActivityManagerService extends IActivityManager.Stub
proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mActivityTaskManager.mPreviousProcessVisibleTime);
}
- if (mHeavyWeightProcess != null && (dumpPackage == null
- || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
- mHeavyWeightProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
+ if (mActivityTaskManager.mHeavyWeightProcess != null && (dumpPackage == null
+ || mActivityTaskManager.mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
+ ((ProcessRecord) mActivityTaskManager.mHeavyWeightProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
}
- for (Map.Entry<String, Integer> entry : mCompatModePackages.getPackages().entrySet()) {
+ for (Map.Entry<String, Integer> entry
+ : mActivityTaskManager.mCompatModePackages.getPackages().entrySet()) {
String pkg = entry.getKey();
int mode = entry.getValue();
if (dumpPackage == null || dumpPackage.equals(pkg)) {
@@ -12563,8 +12422,8 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println();
pw.println(" mHomeProcess: " + mActivityTaskManager.mHomeProcess);
pw.println(" mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
- if (mHeavyWeightProcess != null) {
- pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
+ if (mActivityTaskManager.mHeavyWeightProcess != null) {
+ pw.println(" mHeavyWeightProcess: " + mActivityTaskManager.mHeavyWeightProcess);
}
return true;
@@ -15196,11 +15055,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!replacingPid) {
removeProcessNameLocked(app.processName, app.uid, app);
}
- if (mHeavyWeightProcess == app) {
- mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
- mHeavyWeightProcess.userId, 0));
- mHeavyWeightProcess = null;
- }
+ mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
} else if (!app.removed) {
// This app is persistent, so we need to keep its record around.
// If it is not already on the pending app list, add it there
@@ -15584,7 +15439,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc);
try {
proc.thread.scheduleCreateBackupAgent(app,
- compatibilityInfoForPackageLocked(app), backupMode);
+ compatibilityInfoForPackage(app), backupMode);
} catch (RemoteException e) {
// Will time out on the backup manager side
}
@@ -15683,7 +15538,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (proc.thread != null) {
try {
proc.thread.scheduleDestroyBackupAgent(appInfo,
- compatibilityInfoForPackageLocked(appInfo));
+ compatibilityInfoForPackage(appInfo));
} catch (Exception e) {
Slog.e(TAG, "Exception when unbinding backup agent:");
e.printStackTrace();
@@ -16392,7 +16247,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mServices.forceStopPackageLocked(ssp, userId);
mAtmInternal.onPackageUninstalled(ssp);
- mCompatModePackages.handlePackageUninstalledLocked(ssp);
mBatteryStatsService.notePackageUninstalled(ssp);
}
} else {
@@ -16454,7 +16308,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
final boolean replacing =
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
+ mAtmInternal.onPackageAdded(ssp, replacing);
try {
ApplicationInfo ai = AppGlobals.getPackageManager().
@@ -16471,7 +16325,6 @@ public class ActivityManagerService extends IActivityManager.Stub
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
- mCompatModePackages.handlePackageDataClearedLocked(ssp);
mAtmInternal.onPackageDataCleared(ssp);
}
break;
@@ -17816,7 +17669,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (app == mHeavyWeightProcess) {
+ if (mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
// We don't want to kill the current heavy-weight process.
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
@@ -21097,18 +20950,6 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityManagerService.this.trimApplications();
}
- public int getPackageScreenCompatMode(ApplicationInfo ai) {
- synchronized (ActivityManagerService.this) {
- return mCompatModePackages.computeCompatModeLocked(ai);
- }
- }
-
- public void setPackageScreenCompatMode(ApplicationInfo ai, int mode) {
- synchronized (ActivityManagerService.this) {
- mCompatModePackages.setPackageScreenCompatModeLocked(ai, mode);
- }
- }
-
public void closeSystemDialogs(String reason) {
ActivityManagerService.this.closeSystemDialogs(reason);
}
@@ -21157,6 +20998,38 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void updateCpuStats() {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.updateCpuStats();
+ }
+ }
+
+ @Override
+ public void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.updateUsageStats(activity, uid, userId, resumed);
+ }
+ }
+
+ @Override
+ public void updateForegroundTimeIfOnBattery(
+ String packageName, int uid, long cpuTimeDiff) {
+ synchronized (ActivityManagerService.this) {
+ if (!mBatteryStatsService.isOnBattery()) {
+ return;
+ }
+ final BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
+ synchronized (bsi) {
+ final BatteryStatsImpl.Uid.Proc ps =
+ bsi.getProcessStatsLocked(uid, packageName);
+ if (ps != null) {
+ ps.addForegroundTimeLocked(cpuTimeDiff);
+ }
+ }
+ }
+ }
+
+ @Override
public void sendForegroundProfileChanged(int userId) {
mUserController.sendForegroundProfileChanged(userId);
}
@@ -21216,6 +21089,31 @@ public class ActivityManagerService extends IActivityManager.Stub
return ActivityManagerService.this.getTaskForActivity(token, onlyRoot);
}
}
+
+ @Override
+ public void setBooting(boolean booting) {
+ mBooting = booting;
+ }
+
+ @Override
+ public boolean isBooting() {
+ return mBooting;
+ }
+
+ @Override
+ public void setBooted(boolean booted) {
+ mBooted = booted;
+ }
+
+ @Override
+ public boolean isBooted() {
+ return mBooted;
+ }
+
+ @Override
+ public void finishBooting() {
+ ActivityManagerService.this.finishBooting();
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2199bb71a5f5..77cfb124ec80 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2326,7 +2326,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
final CompatibilityInfo compatInfo =
- service.mAm.compatibilityInfoForPackageLocked(info.applicationInfo);
+ service.compatibilityInfoForPackageLocked(info.applicationInfo);
final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 91e677b2b265..35a1eb8ff616 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -107,6 +107,7 @@ import static java.lang.Integer.MAX_VALUE;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
@@ -151,6 +152,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.wm.ConfigurationContainer;
@@ -1514,14 +1516,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mStackSupervisor.getLaunchTimeTracker().stopFullyDrawnTraceIfNeeded(getWindowingMode());
- mService.mAm.updateCpuStats();
+ mService.updateCpuStats();
if (prev.attachedToProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev),
prev.shortComponentName, "userLeaving=" + userLeaving);
- mService.mAm.updateUsageStats(prev, false);
+ mService.updateUsageStats(prev, false);
mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
@@ -1683,20 +1685,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (prev != null) {
prev.resumeKeyDispatchingLocked();
- if (prev.hasProcess() && prev.cpuTimeAtResume > 0
- && mService.mAm.mBatteryStatsService.isOnBattery()) {
- long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
- if (diff > 0) {
- BatteryStatsImpl bsi = mService.mAm.mBatteryStatsService.getActiveStatistics();
- synchronized (bsi) {
- BatteryStatsImpl.Uid.Proc ps =
- bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
- prev.info.packageName);
- if (ps != null) {
- ps.addForegroundTimeLocked(diff);
- }
- }
- }
+ final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
+ if (prev.hasProcess() && prev.cpuTimeAtResume > 0 && diff > 0) {
+ final Runnable r = PooledLambda.obtainRunnable(
+ ActivityManagerInternal::updateForegroundTimeIfOnBattery,
+ mService.mAmInternal, prev.info.packageName, prev.info.applicationInfo.uid,
+ diff);
+ mService.mH.post(r);
}
prev.cpuTimeAtResume = 0; // reset it
}
@@ -1713,7 +1708,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
}
- void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
+ private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
@@ -2407,7 +2402,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
- if (!mService.mAm.mBooting && !mService.mAm.mBooted) {
+ if (!mService.isBooting() && !mService.isBooted()) {
// Not ready yet!
return false;
}
@@ -2691,7 +2686,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
lastStack == null ? null :lastStack.mResumedActivity;
final ActivityState lastState = next.getState();
- mService.mAm.updateCpuStats();
+ mService.updateCpuStats();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
+ " (in existing)");
@@ -4166,7 +4161,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mWindowManager.notifyAppRelaunchesCleared(r.appToken);
}
- void removeTimeoutsForActivityLocked(ActivityRecord r) {
+ private void removeTimeoutsForActivityLocked(ActivityRecord r) {
mStackSupervisor.removeTimeoutsForActivityLocked(r);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
@@ -4368,12 +4363,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (hadApp) {
if (removeFromApp) {
r.app.removeActivity(r);
- if (mService.mAm.mHeavyWeightProcess != null
- && mService.mAm.mHeavyWeightProcess.getWindowProcessController() == r.app
- && !r.app.hasActivities()) {
- mService.mAm.mHeavyWeightProcess = null;
- mService.mAm.mHandler.sendEmptyMessage(
- ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
+ if (!r.app.hasActivities()) {
+ mService.clearHeavyWeightProcessIfEquals(r.app);
}
if (!r.app.hasActivities()) {
// Update any services we are bound to that might care about whether
@@ -4564,7 +4555,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
r.getTask().taskId, r.shortComponentName,
"proc died without state saved");
if (r.getState() == RESUMED) {
- mService.mAm.updateUsageStats(r, false);
+ mService.updateUsageStats(r, false);
}
}
} else {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8649e83cd932..c887370024ee 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -686,7 +686,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
final Display[] displays = mDisplayManager.getDisplays();
- for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
+ for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
final Display display = displays[displayNdx];
final ActivityDisplay activityDisplay = new ActivityDisplay(this, display);
if (activityDisplay.mDisplayId == DEFAULT_DISPLAY) {
@@ -800,7 +800,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
final ActivityRecord r = topRunningActivityLocked();
- if (mService.mAm.mBooting || !mService.mAm.mBooted) {
+ if (mService.isBooting() || !mService.isBooted()) {
if (r != null && r.idle) {
checkFinishBootingLocked();
}
@@ -832,7 +832,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
- if (!mService.mAm.mBooting && !mService.mAm.mBooted) {
+ if (!mService.isBooting() && !mService.isBooted()) {
// Not ready yet!
return false;
}
@@ -1530,7 +1530,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
r.sleeping = false;
r.forceNewConfig = false;
mService.getAppWarningsLocked().onStartActivity(r);
- r.compat = mService.mAm.compatibilityInfoForPackageLocked(r.info.applicationInfo);
+ r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
ProfilerInfo profilerInfo = null;
if (mService.mAm.mProfileApp != null && mService.mAm.mProfileApp.equals(app.processName)) {
if (mService.mAm.mProfileProc == null || mService.mAm.mProfileProc == app) {
@@ -1591,22 +1591,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
&& mService.mAm.mHasHeavyWeightFeature) {
- // This may be a heavy-weight process! Note that the package
- // manager will ensure that only activity can run in the main
- // process of the .apk, which is the only thing that will be
- // considered heavy-weight.
+ // This may be a heavy-weight process! Note that the package manager will ensure
+ // that only activity can run in the main process of the .apk, which is the only
+ // thing that will be considered heavy-weight.
if (app.processName.equals(app.info.packageName)) {
- if (mService.mAm.mHeavyWeightProcess != null
- && mService.mAm.mHeavyWeightProcess != app) {
- Slog.w(TAG, "Starting new heavy weight process " + app
+ if (mService.mHeavyWeightProcess != null
+ && mService.mHeavyWeightProcess != proc) {
+ Slog.w(TAG, "Starting new heavy weight process " + proc
+ " when already running "
- + mService.mAm.mHeavyWeightProcess);
+ + mService.mHeavyWeightProcess);
}
- mService.mAm.mHeavyWeightProcess = app;
- Message msg = mService.mAm.mHandler.obtainMessage(
- ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
- msg.obj = r;
- mService.mAm.mHandler.sendMessage(msg);
+ mService.setHeavyWeightProcess(r);
}
}
@@ -2053,15 +2048,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
*/
@GuardedBy("mService")
private boolean checkFinishBootingLocked() {
- final boolean booting = mService.mAm.mBooting;
+ final boolean booting = mService.isBooting();
boolean enableScreen = false;
- mService.mAm.mBooting = false;
- if (!mService.mAm.mBooted) {
- mService.mAm.mBooted = true;
+ mService.setBooting(false);
+ if (!mService.isBooted()) {
+ mService.setBooted(true);
enableScreen = true;
}
if (booting || enableScreen) {
- mService.mAm.postFinishBooting(booting, enableScreen);
+ mService.postFinishBooting(booting, enableScreen);
}
return booting;
}
@@ -3682,7 +3677,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityStack stack = r.getStack();
if (isTopDisplayFocusedStack(stack)) {
- mService.mAm.updateUsageStats(r, true);
+ mService.updateUsageStats(r, true);
}
if (allResumedActivitiesComplete()) {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7df255de9ddb..7da0519ef2f0 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1079,9 +1079,9 @@ class ActivityStarter {
// This may be a heavy-weight process! Check to see if we already
// have another, different heavy-weight process running.
if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
- final ProcessRecord heavy = mService.mAm.mHeavyWeightProcess;
- if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
- || !heavy.processName.equals(aInfo.processName))) {
+ final WindowProcessController heavy = mService.mHeavyWeightProcess;
+ if (heavy != null && (heavy.mInfo.uid != aInfo.applicationInfo.uid
+ || !heavy.mName.equals(aInfo.processName))) {
int appCallingUid = callingUid;
if (caller != null) {
ProcessRecord callerApp = mService.mAm.getRecordForAppLocked(caller);
@@ -1109,8 +1109,7 @@ class ActivityStarter {
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
new IntentSender(target));
- heavy.getWindowProcessController().updateIntentForHeavyWeightActivity(
- newIntent);
+ heavy.updateIntentForHeavyWeightActivity(newIntent);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
aInfo.packageName);
newIntent.setFlags(intent.getFlags());
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 6935703dbd04..9acb04be525b 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -125,7 +125,11 @@ import android.app.IActivityController;
import android.app.IActivityTaskManager;
import android.app.IApplicationThread;
import android.app.IAssistDataReceiver;
+import android.app.INotificationManager;
import android.app.ITaskStackListener;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.ProfilerInfo;
import android.app.RemoteAction;
@@ -150,6 +154,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -208,10 +213,13 @@ import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
@@ -266,6 +274,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
ActivityManagerInternal mAmInternal;
UriGrantsManagerInternal mUgmInternal;
private PackageManagerInternal mPmInternal;
+ private ActivityTaskManagerInternal mInternal;
/* Global service lock used by the package the owns this service. */
Object mGlobalLock;
ActivityStackSupervisor mStackSupervisor;
@@ -278,6 +287,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final SparseArray<WindowProcessController> mPidMap = new SparseArray<>();
/** This is the process holding what we currently consider to be the "home" activity. */
WindowProcessController mHomeProcess;
+ /** The currently running heavy-weight process, if any. */
+ WindowProcessController mHeavyWeightProcess = null;
/**
* This is the process holding the activity the user last visited that is in a different process
* from the one they are currently in.
@@ -475,6 +486,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private AppWarnings mAppWarnings;
+ /**
+ * Packages that the user has asked to have run in screen size
+ * compatibility mode instead of filling the screen.
+ */
+ CompatModePackages mCompatModePackages;
+
private FontScaleSettingObserver mFontScaleSettingObserver;
private final class FontScaleSettingObserver extends ContentObserver {
@@ -607,8 +624,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mGlobalLock = mAm;
mH = new H(mAm.mHandlerThread.getLooper());
mUiHandler = new UiHandler();
- mAppWarnings = new AppWarnings(
- this, mUiContext, mH, mUiHandler, SystemServiceManager.ensureSystemDir());
+ final File systemDir = SystemServiceManager.ensureSystemDir();
+ mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir);
+ mCompatModePackages = new CompatModePackages(this, systemDir, mH);
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
@@ -687,7 +705,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
private void start() {
- LocalServices.addService(ActivityTaskManagerInternal.class, new LocalService());
+ mInternal = new LocalService();
+ LocalServices.addService(ActivityTaskManagerInternal.class, mInternal);
}
public static final class Lifecycle extends SystemService {
@@ -1461,16 +1480,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public int getFrontActivityScreenCompatMode() {
enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
- ApplicationInfo ai;
synchronized (mGlobalLock) {
final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivityLocked();
if (r == null) {
return ActivityManager.COMPAT_MODE_UNKNOWN;
}
- ai = r.info.applicationInfo;
+ return mCompatModePackages.computeCompatModeLocked(r.info.applicationInfo);
}
-
- return mAmInternal.getPackageScreenCompatMode(ai);
}
@Override
@@ -1485,9 +1501,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return;
}
ai = r.info.applicationInfo;
+ mCompatModePackages.setPackageScreenCompatModeLocked(ai, mode);
}
-
- mAmInternal.setPackageScreenCompatMode(ai, mode);
}
@Override
@@ -4112,7 +4127,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mVrController.shouldDisableNonVrUiLocked();
}
- void applyUpdateVrModeLocked(ActivityRecord r) {
+ private void applyUpdateVrModeLocked(ActivityRecord r) {
// VR apps are expected to run in a main display. If an app is turning on VR for
// itself, but lives in a dynamic stack, then make sure that it is moved to the main
// fullscreen stack before enabling VR Mode.
@@ -4143,6 +4158,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
});
}
+ @Override
+ public int getPackageScreenCompatMode(String packageName) {
+ enforceNotIsolatedCaller("getPackageScreenCompatMode");
+ synchronized (mGlobalLock) {
+ return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
+ }
+ }
+
+ @Override
+ public void setPackageScreenCompatMode(String packageName, int mode) {
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setPackageScreenCompatMode");
+ synchronized (mGlobalLock) {
+ mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
+ }
+ }
+
+ @Override
+ public boolean getPackageAskScreenCompat(String packageName) {
+ enforceNotIsolatedCaller("getPackageAskScreenCompat");
+ synchronized (mGlobalLock) {
+ return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
+ }
+ }
+
+ @Override
+ public void setPackageAskScreenCompat(String packageName, boolean ask) {
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setPackageAskScreenCompat");
+ synchronized (mGlobalLock) {
+ mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
+ }
+ }
+
ActivityStack getTopDisplayFocusedStack() {
return mStackSupervisor.getTopDisplayFocusedStack();
}
@@ -4808,6 +4857,122 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mH.post(mAmInternal::updateOomAdj);
}
+ void updateCpuStats() {
+ mH.post(mAmInternal::updateCpuStats);
+ }
+
+ void updateUsageStats(ActivityRecord component, boolean resumed) {
+ final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::updateUsageStats,
+ mAmInternal, component.realActivity, component.app.mUid, component.userId, resumed);
+ mH.sendMessage(m);
+ }
+
+ void setBooting(boolean booting) {
+ mAmInternal.setBooting(booting);
+ }
+
+ boolean isBooting() {
+ return mAmInternal.isBooting();
+ }
+
+ void setBooted(boolean booted) {
+ mAmInternal.setBooted(booted);
+ }
+
+ boolean isBooted() {
+ return mAmInternal.isBooted();
+ }
+
+ void postFinishBooting(boolean finishBooting, boolean enableScreen) {
+ mH.post(() -> {
+ if (finishBooting) {
+ mAmInternal.finishBooting();
+ }
+ if (enableScreen) {
+ mInternal.enableScreenAfterBoot(isBooted());
+ }
+ });
+ }
+
+ void setHeavyWeightProcess(ActivityRecord root) {
+ mHeavyWeightProcess = root.app;
+ final Message m = PooledLambda.obtainMessage(
+ ActivityTaskManagerService::postHeavyWeightProcessNotification, this,
+ root.app, root.intent, root.userId);
+ mH.sendMessage(m);
+ }
+
+ void clearHeavyWeightProcessIfEquals(WindowProcessController proc) {
+ if (mHeavyWeightProcess == null || mHeavyWeightProcess != proc) {
+ return;
+ }
+
+ mHeavyWeightProcess = null;
+ final Message m = PooledLambda.obtainMessage(
+ ActivityTaskManagerService::cancelHeavyWeightProcessNotification, this,
+ proc.mUserId);
+ mH.sendMessage(m);
+ }
+
+ private void cancelHeavyWeightProcessNotification(int userId) {
+ final INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+ try {
+ inm.cancelNotificationWithTag("android", null,
+ SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, userId);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error canceling notification for service", e);
+ } catch (RemoteException e) {
+ }
+
+ }
+
+ private void postHeavyWeightProcessNotification(
+ WindowProcessController proc, Intent intent, int userId) {
+ if (proc == null) {
+ return;
+ }
+
+ final INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+
+ try {
+ Context context = mContext.createPackageContext(proc.mInfo.packageName, 0);
+ String text = mContext.getString(R.string.heavy_weight_notification,
+ context.getApplicationInfo().loadLabel(context.getPackageManager()));
+ Notification notification =
+ new Notification.Builder(context,
+ SystemNotificationChannels.HEAVY_WEIGHT_APP)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(text)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(text)
+ .setContentText(
+ mContext.getText(R.string.heavy_weight_notification_detail))
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+ intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(userId)))
+ .build();
+ try {
+ inm.enqueueNotificationWithTag("android", "android", null,
+ SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, notification, userId);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error showing notification for heavy-weight app", e);
+ } catch (RemoteException e) {
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Unable to create context for heavy notification", e);
+ }
+
+ }
+
// TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities
private void startTimeTrackingFocusedActivityLocked() {
final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity();
@@ -4884,6 +5049,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mH.post(() -> mAmInternal.scheduleAppGcs());
}
+ CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+ return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
+ }
+
/**
* Returns the PackageManager. Used by classes hosted by {@link ActivityTaskManagerService}. The
* PackageManager could be unavailable at construction time and therefore needs to be accessed
@@ -5270,6 +5439,28 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
+ public boolean isHeavyWeightProcess(WindowProcessController proc) {
+ synchronized (mGlobalLock) {
+ return proc == mHeavyWeightProcess;
+ }
+ }
+
+ @Override
+ public void clearHeavyWeightProcessIfEquals(WindowProcessController proc) {
+ synchronized (mGlobalLock) {
+ ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals(proc);
+ }
+ }
+
+ @Override
+ public void finishHeavyWeightApp() {
+ synchronized (mGlobalLock) {
+ ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals(
+ mHeavyWeightProcess);
+ }
+ }
+
+ @Override
public boolean isSleeping() {
synchronized (mGlobalLock) {
return isSleepingLocked();
@@ -5378,6 +5569,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void onPackageDataCleared(String name) {
synchronized (mGlobalLock) {
+ mCompatModePackages.handlePackageDataClearedLocked(name);
mAppWarnings.onPackageDataCleared(name);
}
}
@@ -5386,7 +5578,23 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void onPackageUninstalled(String name) {
synchronized (mGlobalLock) {
mAppWarnings.onPackageUninstalled(name);
+ mCompatModePackages.handlePackageUninstalledLocked(name);
+ }
+ }
+
+ @Override
+ public void onPackageAdded(String name, boolean replacing) {
+ synchronized (mGlobalLock) {
+ mCompatModePackages.handlePackageAddedLocked(name, replacing);
}
}
+
+ @Override
+ public CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
+ synchronized (mGlobalLock) {
+ return compatibilityInfoForPackageLocked(ai);
+ }
+ }
+
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 0a7e127dde22..1387f457d2ed 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -302,7 +302,7 @@ public final class BroadcastQueue {
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
- mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
+ mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.getReportedProcState());
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 77efbfc0b387..536f3a93a3f1 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -51,13 +51,13 @@ public final class CompatModePackages {
private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_AM;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
- private final ActivityManagerService mService;
+ private final ActivityTaskManagerService mService;
private final AtomicFile mFile;
// Compatibility state: no longer ask user to select the mode.
- public static final int COMPAT_FLAG_DONT_ASK = 1<<0;
+ private static final int COMPAT_FLAG_DONT_ASK = 1<<0;
// Compatibility state: compatibility mode is enabled.
- public static final int COMPAT_FLAG_ENABLED = 1<<1;
+ private static final int COMPAT_FLAG_ENABLED = 1<<1;
private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
@@ -80,7 +80,7 @@ public final class CompatModePackages {
}
};
- public CompatModePackages(ActivityManagerService service, File systemDir, Handler handler) {
+ public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) {
mService = service;
mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode");
mHandler = new CompatHandler(handler.getLooper());
@@ -317,12 +317,12 @@ public final class CompatModePackages {
scheduleWrite();
- final ActivityStack stack = mService.mActivityTaskManager.getTopDisplayFocusedStack();
+ final ActivityStack stack = mService.getTopDisplayFocusedStack();
ActivityRecord starting = stack.restartPackage(packageName);
// Tell all processes that loaded this package about the change.
- for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mService.mLruProcesses.get(i);
+ for (int i = mService.mAm.mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord app = mService.mAm.mLruProcesses.get(i);
if (!app.pkgList.containsKey(packageName)) {
continue;
}
@@ -346,10 +346,10 @@ public final class CompatModePackages {
}
}
- void saveCompatModes() {
+ private void saveCompatModes() {
HashMap<String, Integer> pkgs;
- synchronized (mService) {
- pkgs = new HashMap<String, Integer>(mPackages);
+ synchronized (mService.mGlobalLock) {
+ pkgs = new HashMap<>(mPackages);
}
FileOutputStream fos = null;
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index d4932f9cf56e..2fdcb5106595 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -25,6 +25,9 @@ public class SystemAudioInitiationActionFromAvr extends HdmiCecFeatureAction {
// State that waits for <Active Source> once send <Request Active Source>.
private static final int STATE_WAITING_FOR_ACTIVE_SOURCE = 1;
+ // State that waits for TV supporting Audio System Mode or not
+ // once received <Active Source>
+ private static final int STATE_WAITING_FOR_TV_SUPPORT = 2;
@VisibleForTesting
static final int MAX_RETRY_COUNT = 5;
@@ -60,6 +63,7 @@ public class SystemAudioInitiationActionFromAvr extends HdmiCecFeatureAction {
if (physicalAddress != getSourcePath()) {
audioSystem().setActiveSource(cmd.getSource(), physicalAddress);
}
+ mState = STATE_WAITING_FOR_TV_SUPPORT;
queryTvSystemAudioModeSupport();
return true;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index b5a9f7416237..326479039ac8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -18,45 +18,11 @@ package com.android.server.inputmethod;
import android.content.ComponentName;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
-
/**
* Input method manager local system service interface.
*/
public abstract class InputMethodManagerInternal {
/**
- * Called by the window manager service when a client process is being attached to the window
- * manager service.
- *
- * <p>The caller must not have WindowManagerService lock. This method internally acquires
- * InputMethodManagerService lock.</p>
- *
- * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
- * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
- * process
- * @param inputContext communication channel for the dummy
- * {@link android.view.inputmethod.InputConnection}
- * @param uid UID of the client process
- * @param pid PID of the client process
- */
- public abstract void addClient(IInputMethodClient client, IInputContext inputContext, int uid,
- int pid);
-
- /**
- * Called by the window manager service when a client process is being attached to the window
- * manager service.
- *
- * <p>The caller must not have WindowManagerService lock. This method internally acquires
- * InputMethodManagerService lock.</p>
- *
- * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
- * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
- * process
- */
- public abstract void removeClient(IInputMethodClient client);
-
- /**
* Called by the power manager to tell the input method manager whether it
* should start watching for wake events.
*/
@@ -78,15 +44,6 @@ public abstract class InputMethodManagerInternal {
public static final InputMethodManagerInternal NOP =
new InputMethodManagerInternal() {
@Override
- public void addClient(IInputMethodClient client, IInputContext inputContext,
- int uid, int pid) {
- }
-
- @Override
- public void removeClient(IInputMethodClient client) {
- }
-
- @Override
public void setInteractive(boolean interactive) {
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a043201100bd..6f5f90a781e3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -401,12 +401,28 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
+ private final InputMethodManagerService mImms;
+ private final IInputMethodClient mClient;
+
+ ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
+ mImms = imms;
+ mClient = client;
+ }
+
+ @Override
+ public void binderDied() {
+ mImms.removeClient(mClient);
+ }
+ }
+
static final class ClientState {
final IInputMethodClient client;
final IInputContext inputContext;
final int uid;
final int pid;
final InputBinding binding;
+ final ClientDeathRecipient clientDeathRecipient;
boolean sessionRequested;
SessionState curSession;
@@ -419,12 +435,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
ClientState(IInputMethodClient _client, IInputContext _inputContext,
- int _uid, int _pid) {
+ int _uid, int _pid, ClientDeathRecipient _clientDeathRecipient) {
client = _client;
inputContext = _inputContext;
uid = _uid;
pid = _pid;
binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
+ clientDeathRecipient = _clientDeathRecipient;
}
}
@@ -1716,9 +1733,39 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- void addClient(ClientState clientState) {
+ /**
+ * Called by each application process as a preparation to start interacting with
+ * {@link InputMethodManagerService}.
+ *
+ * <p>As a general principle, IPCs from the application process that take
+ * {@link InputMethodClient} will be rejected without this step.</p>
+ *
+ * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
+ * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
+ * process
+ * @param inputContext communication channel for the dummy
+ * {@link android.view.inputmethod.InputConnection}
+ */
+ @Override
+ public void addClient(IInputMethodClient client, IInputContext inputContext) {
+ final int callerUid = Binder.getCallingUid();
+ final int callerPid = Binder.getCallingPid();
synchronized (mMethodMap) {
- mClients.put(clientState.client.asBinder(), clientState);
+ // TODO: Optimize this linear search.
+ for (ClientState state : mClients.values()) {
+ if (state.uid == callerUid && state.pid == callerPid) {
+ throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
+ + " is already registered");
+ }
+ }
+ final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
+ try {
+ client.asBinder().linkToDeath(deathRecipient, 0);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(e);
+ }
+ mClients.put(client.asBinder(),
+ new ClientState(client, inputContext, callerUid, callerPid, deathRecipient));
}
}
@@ -1726,6 +1773,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
synchronized (mMethodMap) {
ClientState cs = mClients.remove(client.asBinder());
if (cs != null) {
+ client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
clearClientSessionLocked(cs);
if (mCurClient == cs) {
if (mBoundToMethod) {
@@ -4407,20 +4455,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public void addClient(IInputMethodClient client, IInputContext inputContext, int uid,
- int pid) {
- // Work around Bug 113877122: We need to handle this synchronously. Otherwise, some
- // IMM binder calls from the client process before we register this client.
- mService.addClient(new ClientState(client, inputContext, uid, pid));
- }
-
- @Override
- public void removeClient(IInputMethodClient client) {
- // Handle this synchronously to be consistent with addClient().
- mService.removeClient(client);
- }
-
- @Override
public void setInteractive(boolean interactive) {
// Do everything in handler so as not to block the caller.
mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 4dd2bf25ed67..25f52e7a8501 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -52,8 +52,6 @@ import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.EventInfo;
-import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
import android.service.notification.ZenModeProto;
import android.util.AndroidRuntimeException;
@@ -119,8 +117,6 @@ public class ZenModeHelper {
public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
| SUPPRESSED_EFFECT_NOTIFICATIONS;
- protected String mDefaultRuleEveryNightName;
- protected String mDefaultRuleEventsName;
@VisibleForTesting protected boolean mIsBootComplete;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
@@ -130,9 +126,9 @@ public class ZenModeHelper {
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mNotificationManager = context.getSystemService(NotificationManager.class);
- mDefaultConfig = new ZenModeConfig();
- setDefaultZenRules(mContext);
- mConfig = mDefaultConfig;
+ mDefaultConfig = readDefaultConfig(mContext.getResources());
+ updateDefaultAutomaticRuleNames();
+ mConfig = mDefaultConfig.copy();
mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
mSettingsObserver = new SettingsObserver(mHandler);
@@ -311,7 +307,9 @@ public class ZenModeHelper {
newConfig = mConfig.copy();
ZenRule rule = new ZenRule();
populateZenRule(automaticZenRule, rule, true);
- newConfig.automaticRules.put(rule.id, rule);
+ if (newConfig.automaticRules.put(rule.id, rule) != null) {
+ rule.modified = true;
+ }
if (setConfigLocked(newConfig, reason, rule.component, true)) {
return rule.id;
} else {
@@ -341,7 +339,9 @@ public class ZenModeHelper {
}
}
populateZenRule(automaticZenRule, rule, false);
- newConfig.automaticRules.put(ruleId, rule);
+ if (newConfig.automaticRules.put(ruleId, rule) != null) {
+ rule.modified = true;
+ }
return setConfigLocked(newConfig, reason, rule.component, true);
}
}
@@ -413,17 +413,6 @@ public class ZenModeHelper {
}
}
- public void setDefaultZenRules(Context context) {
- mDefaultConfig = readDefaultConfig(context.getResources());
- appendDefaultRules(mDefaultConfig);
- }
-
- private void appendDefaultRules (ZenModeConfig config) {
- getDefaultRuleNames();
- appendDefaultEveryNightRule(config);
- appendDefaultEventRules(config);
- }
-
// Checks zen rule properties are the same (doesn't check creation time, name nor enabled)
// used to check if default rules were customized or not
private boolean ruleValuesEqual(AutomaticZenRule rule, ZenRule defaultRule) {
@@ -437,22 +426,16 @@ public class ZenModeHelper {
}
protected void updateDefaultZenRules() {
- ZenModeConfig configDefaultRules = new ZenModeConfig();
- appendDefaultRules(configDefaultRules); // "new" localized default rules
- for (String ruleId : ZenModeConfig.DEFAULT_RULE_IDS) {
- AutomaticZenRule currRule = getAutomaticZenRule(ruleId);
- ZenRule defaultRule = configDefaultRules.automaticRules.get(ruleId);
- // if default rule wasn't customized, use localized name instead of previous
- if (ruleValuesEqual(currRule, defaultRule) &&
- !defaultRule.name.equals(currRule.getName())) {
+ updateDefaultAutomaticRuleNames();
+ for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
+ ZenRule currRule = mConfig.automaticRules.get(defaultRule.id);
+ // if default rule wasn't modified, use localized name instead of previous
+ if (!currRule.modified && !defaultRule.name.equals(currRule.name)) {
if (canManageAutomaticZenRule(defaultRule)) {
if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name "
- + "from " + currRule.getName() + " to " + defaultRule.name);
+ + "from " + currRule.name + " to " + defaultRule.name);
// update default rule (if locale changed, name of rule will change)
- AutomaticZenRule defaultAutoRule = createAutomaticZenRule(defaultRule);
- // ensure enabled state is carried over from current rule
- defaultAutoRule.setEnabled(currRule.isEnabled());
- updateAutomaticZenRule(ruleId, defaultAutoRule,
+ updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(defaultRule),
"locale changed");
}
}
@@ -642,7 +625,9 @@ public class ZenModeHelper {
// - doesn't already have default rules and
// - all previous automatic rules were disabled
config.automaticRules = new ArrayMap<>();
- appendDefaultRules(config);
+ for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
+ config.automaticRules.put(rule.id, rule);
+ }
reason += ", reset to default rules";
}
@@ -854,12 +839,16 @@ public class ZenModeHelper {
}
}
- private void getDefaultRuleNames() {
- // on locale-change, these values differ
- mDefaultRuleEveryNightName = mContext.getResources()
- .getString(R.string.zen_mode_default_every_night_name);
- mDefaultRuleEventsName = mContext.getResources()
- .getString(R.string.zen_mode_default_events_name);
+ private void updateDefaultAutomaticRuleNames() {
+ for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
+ if (ZenModeConfig.EVENTS_DEFAULT_RULE_ID.equals(rule.id)) {
+ rule.name = mContext.getResources()
+ .getString(R.string.zen_mode_default_events_name);
+ } else if (ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID.equals(rule.id)) {
+ rule.name = mContext.getResources()
+ .getString(R.string.zen_mode_default_every_night_name);
+ }
+ }
}
@VisibleForTesting
@@ -1001,42 +990,6 @@ public class ZenModeHelper {
return new ZenModeConfig();
}
- private void appendDefaultEveryNightRule(ZenModeConfig config) {
- if (config == null) return;
-
- final ScheduleInfo weeknights = new ScheduleInfo();
- weeknights.days = ZenModeConfig.ALL_DAYS;
- weeknights.startHour = 22;
- weeknights.endHour = 7;
- weeknights.exitAtAlarm = true;
- final ZenRule rule = new ZenRule();
- rule.enabled = false;
- rule.name = mDefaultRuleEveryNightName;
- rule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
- rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- rule.component = ScheduleConditionProvider.COMPONENT;
- rule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
- rule.creationTime = System.currentTimeMillis();
- config.automaticRules.put(rule.id, rule);
- }
-
- private void appendDefaultEventRules(ZenModeConfig config) {
- if (config == null) return;
-
- final EventInfo events = new EventInfo();
- events.calendar = null; // any calendar
- events.reply = EventInfo.REPLY_YES_OR_MAYBE;
- final ZenRule rule = new ZenRule();
- rule.enabled = false;
- rule.name = mDefaultRuleEventsName;
- rule.conditionId = ZenModeConfig.toEventConditionId(events);
- rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- rule.component = EventConditionProvider.COMPONENT;
- rule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
- rule.creationTime = System.currentTimeMillis();
- config.automaticRules.put(rule.id, rule);
- }
-
private static int zenSeverity(int zen) {
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 361416adc4ef..a9f1b5c05a7f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2234,6 +2234,9 @@ class PackageManagerShellCommand extends ShellCommand {
case "--install-location":
sessionParams.installLocation = Integer.parseInt(getNextArg());
break;
+ case "--install-reason":
+ sessionParams.installReason = Integer.parseInt(getNextArg());
+ break;
case "--force-uuid":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
sessionParams.volumeUuid = getNextArg();
@@ -2742,8 +2745,8 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println("");
pw.println(" install [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
- pw.println(" [--originating-uri URI] [---referrer URI]");
- pw.println(" [--abi ABI_NAME] [--force-sdk]");
+ pw.println(" [--install-reason 0/1/2/3/4] [--originating-uri URI]");
+ pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]");
pw.println(" Install an application. Must provide the apk data to install, either as a");
@@ -2768,14 +2771,17 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" --full: cause the app to be installed as a non-ephemeral full app");
pw.println(" --install-location: force the install location:");
pw.println(" 0=auto, 1=internal only, 2=prefer external");
+ pw.println(" --install-reason: indicates why the app is being installed:");
+ pw.println(" 0=unknown, 1=admin policy, 2=device restore,");
+ pw.println(" 3=device setup, 4=user request");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --force-sdk: allow install even when existing app targets platform");
pw.println(" codename but new one targets a final API level");
pw.println("");
pw.println(" install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
- pw.println(" [--originating-uri URI] [---referrer URI]");
- pw.println(" [--abi ABI_NAME] [--force-sdk]");
+ pw.println(" [--install-reason 0/1/2/3/4] [--originating-uri URI]");
+ pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
pw.println(" Like \"install\", but starts an install session. Use \"install-write\"");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3b19beb52e2e..91fd8d0e960d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -125,6 +125,7 @@ import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
+
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -631,9 +632,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
InputConsumer mInputConsumer = null;
- private final WindowFrames mWindowFrames = new WindowFrames();
- private static final Rect mTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
- private static final Rect mTmpRect = new Rect();
+ private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
+ private static final Rect sTmpRect = new Rect();
+ private static final Rect sTmpDockedFrame = new Rect();
+ private static final Rect sTmpNavFrame = new Rect();
+ private static final Rect sTmpLastParentFrame = new Rect();
WindowState mTopFullscreenOpaqueWindowState;
WindowState mTopFullscreenOpaqueOrDimmingWindowState;
@@ -4308,9 +4311,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mDockLayer = 0x10000000;
mStatusBarLayer = -1;
- mWindowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
- mWindowFrames.setParentFrameWasClippedByDisplayCutout(false);
-
if (displayFrames.mDisplayId == DEFAULT_DISPLAY) {
// For purposes of putting out fake window up to steal focus, we will
// drive nav being hidden only by whether it is requested.
@@ -4377,12 +4377,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return;
}
- mTmpRect.setEmpty();
- mWindowFrames.setFrames(displayFrames.mDock /* parentFrame */,
- displayFrames.mDock /* displayFrame */, displayFrames.mDock /* overscanFrame */,
- displayFrames.mDock /* contentFrame */, displayFrames.mDock /* visibleFrame */,
- mTmpRect /* decorFrame */, displayFrames.mDock /* stableFrame */,
- displayFrames.mDock /* outsetFrame */);
+ sTmpRect.setEmpty();
+ sTmpDockedFrame.set(displayFrames.mDock);
final int displayId = displayFrames.mDisplayId;
final Rect dockFrame = displayFrames.mDock;
@@ -4396,7 +4392,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
continue;
}
- w.computeFrameLw(mWindowFrames);
+ w.getWindowFrames().setFrames(sTmpDockedFrame /* parentFrame */,
+ sTmpDockedFrame /* displayFrame */, sTmpDockedFrame /* overscanFrame */,
+ sTmpDockedFrame /* contentFrame */, sTmpDockedFrame /* visibleFrame */,
+ sTmpRect /* decorFrame */, sTmpDockedFrame /* stableFrame */,
+ sTmpDockedFrame /* outsetFrame */);
+ w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ w.computeFrameLw();
final Rect frame = w.getFrameLw();
if (frame.left <= 0 && frame.top <= 0) {
@@ -4448,17 +4450,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return false;
}
// apply any navigation bar insets
- mTmpRect.setEmpty();
- mWindowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
+ sTmpRect.setEmpty();
+ mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
displayFrames.mUnrestricted /* displayFrame */,
displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
- displayFrames.mStable /* visibleFrame */, mTmpRect /* decorFrame */,
+ displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
-
+ mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
mStatusBarLayer = mStatusBar.getSurfaceLayer();
// Let the status bar determine its size.
- mStatusBar.computeFrameLw(mWindowFrames);
+ mStatusBar.computeFrameLw();
// For layout, the status bar is always at the top with our fixed height.
displayFrames.mStable.top = displayFrames.mUnrestricted.top
@@ -4468,11 +4470,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
displayFrames.mDisplayCutoutSafe.top);
// Tell the bar controller where the collapsed status bar content is
- mTmpRect.set(mStatusBar.getContentFrameLw());
- mTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
- mTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
- mTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
- mStatusBarController.setContentFrame(mTmpRect);
+ sTmpRect.set(mStatusBar.getContentFrameLw());
+ sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+ sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
+ sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+ mStatusBarController.setContentFrame(sTmpRect);
boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
boolean statusBarTranslucent = (sysui
@@ -4512,7 +4514,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return false;
}
- final Rect navigationFrame = mWindowFrames.mParentFrame;
+ final Rect navigationFrame = sTmpNavFrame;
boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
// Force the navigation bar to its appropriate place and size. We need to do this directly,
// instead of relying on it to bubble up from the nav bar, because this needs to change
@@ -4523,7 +4525,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Rect dockFrame = displayFrames.mDock;
mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
- final Rect cutoutSafeUnrestricted = mTmpRect;
+ final Rect cutoutSafeUnrestricted = sTmpRect;
cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
@@ -4605,15 +4607,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
displayFrames.mContent.set(dockFrame);
mStatusBarLayer = mNavigationBar.getSurfaceLayer();
// And compute the final frame.
- mTmpRect.setEmpty();
- mWindowFrames.setFrames(navigationFrame /* parentFrame */,
+ sTmpRect.setEmpty();
+ mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
displayFrames.mDisplayCutoutSafe /* contentFrame */,
- navigationFrame /* visibleFrame */, mTmpRect /* decorFrame */,
+ navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
navigationFrame /* stableFrame */,
displayFrames.mDisplayCutoutSafe /* outsetFrame */);
-
- mNavigationBar.computeFrameLw(mWindowFrames);
+ mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ mNavigationBar.computeFrameLw();
mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
@@ -4744,17 +4746,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
- final Rect pf = mWindowFrames.mParentFrame;
- final Rect df = mWindowFrames.mDisplayFrame;
- final Rect of = mWindowFrames.mOverscanFrame;
- final Rect cf = mWindowFrames.mContentFrame;
- final Rect vf = mWindowFrames.mVisibleFrame;
- final Rect dcf = mWindowFrames.mDecorFrame;
- final Rect sf = mWindowFrames.mStableFrame;
+ final WindowFrames windowFrames = win.getWindowFrames();
+
+ windowFrames.setHasOutsets(false);
+ sTmpLastParentFrame.set(windowFrames.mParentFrame);
+ final Rect pf = windowFrames.mParentFrame;
+ final Rect df = windowFrames.mDisplayFrame;
+ final Rect of = windowFrames.mOverscanFrame;
+ final Rect cf = windowFrames.mContentFrame;
+ final Rect vf = windowFrames.mVisibleFrame;
+ final Rect dcf = windowFrames.mDecorFrame;
+ final Rect sf = windowFrames.mStableFrame;
dcf.setEmpty();
- mWindowFrames.mOutsetFrame.setEmpty();
- mWindowFrames.setParentFrameWasClippedByDisplayCutout(false);
- mWindowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
+ windowFrames.setParentFrameWasClippedByDisplayCutout(false);
+ windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
final boolean hasNavBar = (isDefaultDisplay && mDefaultDisplayPolicy.hasNavigationBar()
&& mNavigationBar != null && mNavigationBar.isVisibleLw());
@@ -4774,7 +4779,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cf.set(displayFrames.mDock);
of.set(displayFrames.mDock);
df.set(displayFrames.mDock);
- pf.set(displayFrames.mDock);
+ windowFrames.mParentFrame.set(displayFrames.mDock);
// IM dock windows layout below the nav bar...
pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
// ...with content insets above the nav bar
@@ -4876,9 +4881,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
? displayFrames.mRestricted.bottom
: displayFrames.mUnrestricted.bottom;
- if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
- "Laying out status bar window: (%d,%d - %d,%d)",
- pf.left, pf.top, pf.right, pf.bottom));
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
} else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
&& type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
// Asking to layout into the overscan region, so give it that pure
@@ -4950,17 +4953,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.bottom = df.bottom = of.bottom = cf.bottom =
displayFrames.mRestricted.bottom;
}
- if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
- "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
- pf.left, pf.top, pf.right, pf.bottom));
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
} else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
// The navigation bar has Real Ultimate Power.
of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
- if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
- "Laying out navigation bar window: (%d,%d - %d,%d)",
- pf.left, pf.top, pf.right, pf.bottom));
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
} else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
&& ((fl & FLAG_FULLSCREEN) != 0)) {
// Fullscreen secure system overlays get what they ask for. Screenshot region
@@ -5087,7 +5086,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
- final Rect displayCutoutSafeExceptMaybeBars = mTmpDisplayCutoutSafeExceptMaybeBarsRect;
+ final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
&& cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
@@ -5122,9 +5121,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// They will later be cropped or shifted using the displayFrame in WindowState,
// which prevents overlap with the DisplayCutout.
if (!attachedInParent && !floatingInScreenWindow) {
- mTmpRect.set(pf);
+ sTmpRect.set(pf);
pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
- mWindowFrames.setParentFrameWasClippedByDisplayCutout(!mTmpRect.equals(pf));
+ windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
}
// Make sure that NO_LIMITS windows clipped to the display don't extend under the
// cutout.
@@ -5152,8 +5151,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// apply the outsets to floating dialogs, because they wouldn't make sense there.
final boolean useOutsets = shouldUseOutsets(attrs, fl);
if (isDefaultDisplay && useOutsets) {
- final Rect osf = mWindowFrames.mOutsetFrame;
+ final Rect osf = windowFrames.mOutsetFrame;
osf.set(cf.left, cf.top, cf.right, cf.bottom);
+ windowFrames.setHasOutsets(true);
int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
if (outset > 0) {
int rotation = displayFrames.mRotation;
@@ -5180,9 +5180,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
+ " dcf=" + dcf.toShortString()
+ " sf=" + sf.toShortString()
- + " osf=" + mWindowFrames.mOutsetFrame.toShortString());
+ + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
+
+ if (!sTmpLastParentFrame.equals(pf)) {
+ windowFrames.setContentChanged(true);
+ }
- win.computeFrameLw(mWindowFrames);
+ win.computeFrameLw();
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b55adeb32729..1fcdd63c4488 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -63,12 +63,10 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -95,7 +93,6 @@ import com.android.internal.policy.IShortcutService;
import com.android.server.wm.DisplayFrames;
import com.android.server.wm.DisplayRotation;
import com.android.server.wm.WindowFrames;
-import com.android.server.wm.utils.WmDisplayCutout;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -201,10 +198,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* getFrame() if so desired. Must be called with the window manager
* lock held.
*
- * @param windowFrames Container for all the window frames that affect how the window is
- * laid out.
*/
- public void computeFrameLw(WindowFrames windowFrames);
+ public void computeFrameLw();
/**
* Retrieve the current frame of the window that has been assigned by
@@ -477,6 +472,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* Writes {@link com.android.server.wm.IdentifierProto} to stream.
*/
void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
+
+ /**
+ * @return The {@link WindowFrames} associated with this {@link WindowState}
+ */
+ WindowFrames getWindowFrames();
}
/**
@@ -1167,7 +1167,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
default void layoutWindowLw(
WindowState win, WindowState attached, DisplayFrames displayFrames) {}
-
/**
* Return the layout hints for a newly added window. These values are computed on the
* most recent layout, so they are not guaranteed to be correct.
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 180f34355c94..9f69702911c9 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -23,11 +23,11 @@ import android.annotation.NonNull;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.Pair;
+import android.util.Slog;
import android.util.apk.ApkSignatureVerifier;
import android.util.apk.ByteBufferFactory;
import android.util.apk.SignatureNotFoundException;
-import android.util.Pair;
-import android.util.Slog;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -85,7 +85,7 @@ abstract public class VerityUtils {
*/
public static byte[] generateFsverityRootHash(@NonNull String apkPath)
throws NoSuchAlgorithmException, DigestException, IOException {
- return ApkSignatureVerifier.generateFsverityRootHash(apkPath);
+ return ApkSignatureVerifier.generateApkVerityRootHash(apkPath);
}
/**
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 5e3fe0a119ff..bfa03ca9f2be 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1031,7 +1031,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
looperStats.reset();
for (LooperStats.ExportedEntry entry : entries) {
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(1000); // uid collection not implemented yet
+ e.writeInt(entry.workSourceUid);
e.writeString(entry.handlerClassName);
e.writeString(entry.threadName);
e.writeString(entry.messageName);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 83075ed24e33..524ca170336f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -23,6 +23,8 @@ import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
@@ -267,6 +269,9 @@ public abstract class ActivityTaskManagerInternal {
public abstract void onProcessRemoved(String name, int uid);
public abstract void onCleanUpApplicationRecord(WindowProcessController proc);
public abstract int getTopProcessState();
+ public abstract boolean isHeavyWeightProcess(WindowProcessController proc);
+ public abstract void clearHeavyWeightProcessIfEquals(WindowProcessController proc);
+ public abstract void finishHeavyWeightApp();
public abstract boolean isSleeping();
public abstract boolean isShuttingDown();
@@ -281,4 +286,7 @@ public abstract class ActivityTaskManagerInternal {
public abstract void onPackageDataCleared(String name);
public abstract void onPackageUninstalled(String name);
+ public abstract void onPackageAdded(String name, boolean replacing);
+
+ public abstract CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d518549859a0..6aca4640f160 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -571,7 +571,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (!w.mLayoutAttached) {
if (mTmpInitial) {
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
- w.mContentChanged = false;
+ w.resetContentChanged();
}
if (w.mAttrs.type == TYPE_DREAM) {
// Don't layout windows behind a dream, so that if it does stuff like hide
@@ -616,7 +616,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|| w.mLayoutNeeded) {
if (mTmpInitial) {
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
- w.mContentChanged = false;
+ w.resetContentChanged();
}
w.mLayoutNeeded = false;
w.prelayout();
@@ -699,7 +699,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final WindowStateAnimator winAnimator = w.mWinAnimator;
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
- w.mContentChanged = false;
+ w.resetContentChanged();
// Moved from updateWindowsAndWallpaperLocked().
if (w.mHasSurface) {
@@ -3251,7 +3251,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// TODO(b/68392460): We should screenshot Task controls directly
// but it's difficult at the moment as the Task doesn't have the
// correct size set.
- final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, 0, 1, inRotation, rot);
+ final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, inRotation, rot);
if (bitmap == null) {
Slog.w(TAG_WM, "Failed to take screenshot");
return null;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index f9a71d3d850d..acc9c038bd9c 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -38,7 +38,6 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.Trace;
import android.os.UserHandle;
import android.util.MergedConfiguration;
@@ -56,10 +55,6 @@ import android.view.SurfaceSession;
import android.view.WindowManager;
import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
-import com.android.server.LocalServices;
-import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.WindowManagerService.H;
import java.io.PrintWriter;
@@ -73,8 +68,6 @@ import java.util.Set;
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final WindowManagerService mService;
final IWindowSessionCallback mCallback;
- final IInputMethodClient mClient;
- final InputMethodManagerInternal mInputMethodManagerInternal;
final int mUid;
final int mPid;
private final String mStringName;
@@ -95,17 +88,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
private String mPackageName;
private String mRelayoutTag;
- public Session(WindowManagerService service, IWindowSessionCallback callback,
- IInputMethodClient client, IInputContext inputContext) {
+ public Session(WindowManagerService service, IWindowSessionCallback callback) {
mService = service;
mCallback = callback;
- mClient = client;
- // Depending on the timing when Session object gets called and SystemServer#mFactoryTestMode
- // this could be null, right?
- final InputMethodManagerInternal immInternal =
- LocalServices.getService(InputMethodManagerInternal.class);
- mInputMethodManagerInternal =
- immInternal != null ? immInternal : InputMethodManagerInternal.NOP;
mUid = Binder.getCallingUid();
mPid = Binder.getCallingPid();
mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
@@ -134,12 +119,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
sb.append("}");
mStringName = sb.toString();
- mInputMethodManagerInternal.addClient(client, inputContext, mUid, mPid);
try {
- client.asBinder().linkToDeath(this, 0);
+ mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
// The caller has died, so we can just forget about this.
- mInputMethodManagerInternal.removeClient(client);
+ // Hmmm, should we call killSessionLocked()??
}
}
@@ -159,9 +143,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void binderDied() {
- mInputMethodManagerInternal.removeClient(mClient);
synchronized(mService.mWindowMap) {
- mClient.asBinder().unlinkToDeath(this, 0);
+ mCallback.asBinder().unlinkToDeath(this, 0);
mClientDead = true;
killSessionLocked();
}
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index cbe7d9d05e28..20a874b7d0e8 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -36,7 +36,6 @@ import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
-import android.view.WindowManager;
import com.android.server.wm.utils.InsetUtils;
import com.android.server.wm.utils.WmDisplayCutout;
@@ -191,6 +190,10 @@ public class WindowFrames {
private final Rect mTmpRect = new Rect();
+ private boolean mHasOutsets;
+
+ private boolean mContentChanged;
+
public WindowFrames() {
}
@@ -237,11 +240,9 @@ public class WindowFrames {
* Calculates the outsets for this windowFrame. The outsets are calculated by the area between
* the {@link #mOutsetFrame} and the {@link #mContentFrame}. If there are no outsets, then
* {@link #mOutsets} is set to empty.
- *
- * @param hasOutsets Whether this frame has outsets.
*/
- void calculateOutsets(boolean hasOutsets) {
- if (hasOutsets) {
+ void calculateOutsets() {
+ if (mHasOutsets) {
InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
} else {
mOutsets.setEmpty();
@@ -249,7 +250,8 @@ public class WindowFrames {
}
/**
- * Calculate the insets for the type {@link WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
+ * Calculate the insets for the type
+ * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
*
* @param cutoutInsets The insets for the cutout.
*/
@@ -367,6 +369,28 @@ public class WindowFrames {
mLastContentInsets.set(-1, -1, -1, -1);
}
+ /**
+ * Sets whether the frame has outsets.
+ */
+ public void setHasOutsets(boolean hasOutsets) {
+ mHasOutsets = hasOutsets;
+ }
+
+ /**
+ * Sets whether the content has changed. This means that either the size or parent frame has
+ * changed.
+ */
+ public void setContentChanged(boolean contentChanged) {
+ mContentChanged = contentChanged;
+ }
+
+ /**
+ * @see #setContentChanged(boolean)
+ */
+ boolean hasContentChanged() {
+ return mContentChanged;
+ }
+
public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
mParentFrame.writeToProto(proto, PARENT_FRAME);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 711f66ad4d9a..71ce1d9e2ea7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -232,8 +232,6 @@ import com.android.internal.policy.IShortcutService;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.LatencyTracker;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
@@ -5037,12 +5035,8 @@ public class WindowManagerService extends IWindowManager.Stub
// -------------------------------------------------------------
@Override
- public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
- IInputContext inputContext) {
- if (client == null) throw new IllegalArgumentException("null client");
- if (inputContext == null) throw new IllegalArgumentException("null inputContext");
- Session session = new Session(this, callback, client, inputContext);
- return session;
+ public IWindowSession openSession(IWindowSessionCallback callback) {
+ return new Session(this, callback);
}
@Override
@@ -5075,9 +5069,7 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- if (displayId != DEFAULT_DISPLAY) {
- throw new IllegalArgumentException("Can only set the default display");
- }
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized(mWindowMap) {
@@ -5110,9 +5102,7 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- if (displayId != DEFAULT_DISPLAY) {
- throw new IllegalArgumentException("Can only set the default display");
- }
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized(mWindowMap) {
@@ -5192,9 +5182,7 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- if (displayId != DEFAULT_DISPLAY) {
- throw new IllegalArgumentException("Can only set the default display");
- }
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized(mWindowMap) {
@@ -5241,9 +5229,6 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- if (displayId != DEFAULT_DISPLAY) {
- throw new IllegalArgumentException("Can only set the default display");
- }
final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
@@ -5272,9 +5257,6 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- if (displayId != DEFAULT_DISPLAY) {
- throw new IllegalArgumentException("Can only set the default display");
- }
final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser",
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 6e0ccfd5d2db..831418b4b2b4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -20,7 +20,6 @@ import static android.os.Build.IS_USER;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -28,10 +27,6 @@ import android.util.DisplayMetrics;
import android.view.Display;
import android.view.IWindowManager;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -87,21 +82,48 @@ public class WindowManagerShellCommand extends ShellCommand {
return -1;
}
+ private int getDisplayId(String opt) {
+ int displayId = Display.DEFAULT_DISPLAY;
+ String option = "-d".equals(opt) ? opt : getNextOption();
+ if (option != null && "-d".equals(option)) {
+ try {
+ displayId = Integer.parseInt(getNextArgRequired());
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad number " + e);
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println("Error: " + e);
+ }
+ }
+ return displayId;
+ }
+
+ private void printInitialDisplaySize(PrintWriter pw , int displayId) {
+ final Point initialSize = new Point();
+ final Point baseSize = new Point();
+
+ try {
+ mInterface.getInitialDisplaySize(displayId, initialSize);
+ mInterface.getBaseDisplaySize(displayId, baseSize);
+ pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
+ if (!initialSize.equals(baseSize)) {
+ pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
+ }
+ } catch (RemoteException e) {
+ // Can't call getInitialDisplaySize() on IWindowManager or
+ // Can't call getBaseDisplaySize() on IWindowManager
+ pw.println("Remote exception: " + e);
+ }
+ }
+
private int runDisplaySize(PrintWriter pw) throws RemoteException {
String size = getNextArg();
int w, h;
+ final int displayId = getDisplayId(size);
if (size == null) {
- Point initialSize = new Point();
- Point baseSize = new Point();
- try {
- mInterface.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
- mInterface.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
- pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
- if (!initialSize.equals(baseSize)) {
- pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
- }
- } catch (RemoteException e) {
- }
+ printInitialDisplaySize(pw, displayId);
+ return 0;
+ } else if ("-d".equals(size)) {
+ printInitialDisplaySize(pw, displayId);
return 0;
} else if ("reset".equals(size)) {
w = h = -1;
@@ -114,8 +136,8 @@ public class WindowManagerShellCommand extends ShellCommand {
String wstr = size.substring(0, div);
String hstr = size.substring(div+1);
try {
- w = parseDimension(wstr);
- h = parseDimension(hstr);
+ w = parseDimension(wstr, displayId);
+ h = parseDimension(hstr, displayId);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: bad number " + e);
return -1;
@@ -123,27 +145,38 @@ public class WindowManagerShellCommand extends ShellCommand {
}
if (w >= 0 && h >= 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- mInterface.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
+ mInterface.setForcedDisplaySize(displayId, w, h);
} else {
- mInterface.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
+ mInterface.clearForcedDisplaySize(displayId);
}
return 0;
}
+ private void printInitialDisplayDensity(PrintWriter pw , int displayId) {
+ try {
+ final int initialDensity = mInterface.getInitialDisplayDensity(displayId);
+ final int baseDensity = mInterface.getBaseDisplayDensity(displayId);
+ pw.println("Physical density: " + initialDensity);
+ if (initialDensity != baseDensity) {
+ pw.println("Override density: " + baseDensity);
+ }
+ } catch (RemoteException e) {
+ // Can't call getInitialDisplayDensity() on IWindowManager or
+ // Can't call getBaseDisplayDensity() on IWindowManager
+ pw.println("Remote exception: " + e);
+ }
+ }
+
private int runDisplayDensity(PrintWriter pw) throws RemoteException {
String densityStr = getNextArg();
int density;
+ final int displayId = getDisplayId(densityStr);
+
if (densityStr == null) {
- try {
- int initialDensity = mInterface.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
- int baseDensity = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
- pw.println("Physical density: " + initialDensity);
- if (initialDensity != baseDensity) {
- pw.println("Override density: " + baseDensity);
- }
- } catch (RemoteException e) {
- }
+ printInitialDisplayDensity(pw, displayId);
+ return 0;
+ } else if ("-d".equals(densityStr)) {
+ printInitialDisplayDensity(pw, displayId);
return 0;
} else if ("reset".equals(densityStr)) {
density = -1;
@@ -161,11 +194,10 @@ public class WindowManagerShellCommand extends ShellCommand {
}
if (density > 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- mInterface.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
+ mInterface.setForcedDisplayDensityForUser(displayId, density,
UserHandle.USER_CURRENT);
} else {
- mInterface.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
+ mInterface.clearForcedDisplayDensityForUser(displayId,
UserHandle.USER_CURRENT);
}
return 0;
@@ -174,6 +206,7 @@ public class WindowManagerShellCommand extends ShellCommand {
private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
String overscanStr = getNextArgRequired();
Rect rect = new Rect();
+ final int displayId = getDisplayId(overscanStr);
if ("reset".equals(overscanStr)) {
rect.set(0, 0, 0, 0);
} else {
@@ -190,17 +223,16 @@ public class WindowManagerShellCommand extends ShellCommand {
rect.bottom = Integer.parseInt(matcher.group(4));
}
- mInterface.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right,
- rect.bottom);
+ mInterface.setOverscan(displayId, rect.left, rect.top, rect.right, rect.bottom);
return 0;
}
private int runDisplayScaling(PrintWriter pw) throws RemoteException {
String scalingStr = getNextArgRequired();
if ("auto".equals(scalingStr)) {
- mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0);
+ mInterface.setForcedDisplayScalingMode(getDisplayId(scalingStr), 0);
} else if ("off".equals(scalingStr)) {
- mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
+ mInterface.setForcedDisplayScalingMode(getDisplayId(scalingStr), 1);
} else {
getErrPrintWriter().println("Error: scaling must be 'auto' or 'off'");
return -1;
@@ -213,14 +245,14 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
- private int parseDimension(String s) throws NumberFormatException {
+ private int parseDimension(String s, int displayId) throws NumberFormatException {
if (s.endsWith("px")) {
return Integer.parseInt(s.substring(0, s.length() - 2));
}
if (s.endsWith("dp")) {
int density;
try {
- density = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
+ density = mInterface.getBaseDisplayDensity(displayId);
} catch (RemoteException e) {
density = DisplayMetrics.DENSITY_DEFAULT;
}
@@ -236,14 +268,14 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println("Window manager (window) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" size [reset|WxH|WdpxHdp]");
+ pw.println(" size [reset|WxH|WdpxHdp] [-d DISPLAY_ID]");
pw.println(" Return or override display size.");
pw.println(" width and height in pixels unless suffixed with 'dp'.");
- pw.println(" density [reset|DENSITY]");
+ pw.println(" density [reset|DENSITY] [-d DISPLAY_ID]");
pw.println(" Return or override display density.");
- pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM]");
+ pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]");
pw.println(" Set overscan area for display.");
- pw.println(" scaling [off|auto]");
+ pw.println(" scaling [off|auto] [-d DISPLAY_ID]");
pw.println(" Set display scaling mode.");
pw.println(" dismiss-keyguard");
pw.println(" Dismiss the keyguard, prompting user for auth if necessary.");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5272b663c2aa..f1ddda777e8f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -359,8 +359,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
private final Rect mInsetFrame = new Rect();
- boolean mContentChanged;
-
// If a window showing a wallpaper: the requested offset for the
// wallpaper; if a wallpaper window: the currently applied offset.
float mWallpaperX = -1;
@@ -787,7 +785,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
@Override
- public void computeFrameLw(WindowFrames windowFrames) {
+ public void computeFrameLw() {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
@@ -796,8 +794,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
mHaveFrame = true;
- mWindowFrames.setParentFrameWasClippedByDisplayCutout(
- windowFrames.parentFrameWasClippedByDisplayCutout());
final Task task = getTask();
final boolean inFullscreenContainer = inFullscreenContainer();
@@ -827,10 +823,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final int layoutYDiff;
if (inFullscreenContainer || layoutInParentFrame()) {
// We use the parent frame as the containing frame for fullscreen and child windows
- mWindowFrames.mContainingFrame.set(windowFrames.mParentFrame);
- mWindowFrames.mDisplayFrame.set(windowFrames.mDisplayFrame);
- layoutDisplayFrame = windowFrames.mDisplayFrame;
- layoutContainingFrame = windowFrames.mParentFrame;
+ mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame);
+ layoutDisplayFrame = mWindowFrames.mDisplayFrame;
+ layoutContainingFrame = mWindowFrames.mParentFrame;
layoutXDiff = 0;
layoutYDiff = 0;
} else {
@@ -849,17 +844,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// IME is up and obscuring this window. Adjust the window position so it is visible.
if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) {
if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom
- > windowFrames.mContentFrame.bottom) {
+ > mWindowFrames.mContentFrame.bottom) {
// In freeform we want to move the top up directly.
// TODO: Investigate why this is contentFrame not parentFrame.
mWindowFrames.mContainingFrame.top -= mWindowFrames.mContainingFrame.bottom
- - windowFrames.mContentFrame.bottom;
+ - mWindowFrames.mContentFrame.bottom;
} else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom
- > windowFrames.mParentFrame.bottom) {
+ > mWindowFrames.mParentFrame.bottom) {
// But in docked we want to behave like fullscreen and behave as if the task
// were given smaller bounds for the purposes of layout. Skip adjustments for
// the pinned stack, they are handled separately in the PinnedStackController.
- mWindowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom;
+ mWindowFrames.mContainingFrame.bottom = mWindowFrames.mParentFrame.bottom;
}
}
@@ -868,7 +863,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// if it wasn't set already. No need to intersect it with the (visible)
// "content frame" since it is allowed to be outside the visible desktop.
if (mWindowFrames.mContainingFrame.isEmpty()) {
- mWindowFrames.mContainingFrame.set(windowFrames.mContentFrame);
+ mWindowFrames.mContainingFrame.set(mWindowFrames.mContentFrame);
}
}
@@ -878,10 +873,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// PIP edge case: When going from pinned to fullscreen, we apply a
// tempInsetFrame for the full task - but we're still at the start of the animation.
// To prevent a jump if there's a letterbox, restrict to the parent frame.
- mInsetFrame.intersectUnchecked(windowFrames.mParentFrame);
- mWindowFrames.mContainingFrame.intersectUnchecked(windowFrames.mParentFrame);
+ mInsetFrame.intersectUnchecked(mWindowFrames.mParentFrame);
+ mWindowFrames.mContainingFrame.intersectUnchecked(mWindowFrames.mParentFrame);
}
+ layoutDisplayFrame = new Rect(mWindowFrames.mDisplayFrame);
mWindowFrames.mDisplayFrame.set(mWindowFrames.mContainingFrame);
layoutXDiff =
!mInsetFrame.isEmpty() ? mInsetFrame.left - mWindowFrames.mContainingFrame.left
@@ -892,41 +888,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
layoutContainingFrame =
!mInsetFrame.isEmpty() ? mInsetFrame : mWindowFrames.mContainingFrame;
mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight);
- subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame,
- windowFrames.mDisplayFrame, mTmpRect);
+ subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame,
+ mTmpRect);
if (!layoutInParentFrame()) {
subtractInsets(mWindowFrames.mContainingFrame, layoutContainingFrame,
- windowFrames.mParentFrame, mTmpRect);
- subtractInsets(mInsetFrame, layoutContainingFrame, windowFrames.mParentFrame,
+ mWindowFrames.mParentFrame, mTmpRect);
+ subtractInsets(mInsetFrame, layoutContainingFrame, mWindowFrames.mParentFrame,
mTmpRect);
}
- layoutDisplayFrame = windowFrames.mDisplayFrame;
layoutDisplayFrame.intersect(layoutContainingFrame);
}
final int pw = mWindowFrames.mContainingFrame.width();
final int ph = mWindowFrames.mContainingFrame.height();
- if (!mWindowFrames.mParentFrame.equals(windowFrames.mParentFrame)) {
- //Slog.i(TAG_WM, "Window " + this + " content frame from " + mParentFrame
- // + " to " + parentFrame);
- mWindowFrames.mParentFrame.set(windowFrames.mParentFrame);
- mContentChanged = true;
- }
if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
mLastRequestedWidth = mRequestedWidth;
mLastRequestedHeight = mRequestedHeight;
- mContentChanged = true;
- }
-
- mWindowFrames.mOverscanFrame.set(windowFrames.mOverscanFrame);
- mWindowFrames.mContentFrame.set(windowFrames.mContentFrame);
- mWindowFrames.mVisibleFrame.set(windowFrames.mVisibleFrame);
- mWindowFrames.mDecorFrame.set(windowFrames.mDecorFrame);
- mWindowFrames.mStableFrame.set(windowFrames.mStableFrame);
- final boolean hasOutsets = !windowFrames.mOutsetFrame.isEmpty();
- if (hasOutsets) {
- mWindowFrames.mOutsetFrame.set(windowFrames.mOutsetFrame);
+ mWindowFrames.setContentChanged(true);
}
final int fw = mWindowFrames.mFrame.width();
@@ -935,7 +914,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
// Calculate the outsets before the content frame gets shrinked to the window frame.
- mWindowFrames.calculateOutsets(hasOutsets);
+ mWindowFrames.calculateOutsets();
// Make sure the content and visible frames are inside of the
// final window frame.
@@ -997,7 +976,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
- final WmDisplayCutout c = windowFrames.mDisplayCutout.calculateRelativeTo(
+ final WmDisplayCutout c = mWindowFrames.mDisplayCutout.calculateRelativeTo(
mWindowFrames.mDisplayFrame);
mWindowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets());
} else {
@@ -1006,7 +985,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
mWindowFrames.setDisplayCutout(
- windowFrames.mDisplayCutout.calculateRelativeTo(mWindowFrames.mFrame));
+ mWindowFrames.mDisplayCutout.calculateRelativeTo(mWindowFrames.mFrame));
// Offset the actual frame by the amount layout frame is off.
mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
@@ -1733,7 +1712,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
*/
private boolean hasMoved() {
- return mHasSurface && (mContentChanged || mMovedByResize)
+ return mHasSurface && (mWindowFrames.hasContentChanged() || mMovedByResize)
&& !mAnimatingExit
&& (mWindowFrames.mFrame.top != mWindowFrames.mLastFrame.top
|| mWindowFrames.mFrame.left != mWindowFrames.mLastFrame.left)
@@ -4762,6 +4741,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mWindowFrames.mVisibleInsets;
}
+ @Override
+ public WindowFrames getWindowFrames() {
+ return mWindowFrames;
+ }
+
+ void resetContentChanged() {
+ mWindowFrames.setContentChanged(false);
+ }
+
private final class MoveAnimationSpec implements AnimationSpec {
private final long mDuration;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4c71d65115f0..e76afa3c144a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6019,7 +6019,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
if (!success) {
Slog.w(LOG_TAG, "Couldn't remove user " + userId);
- } else if (isManagedProfile(userId)) {
+ } else if (isManagedProfile(userId) && !TextUtils.isEmpty(wipeReasonForUser)) {
sendWipeProfileNotification(wipeReasonForUser);
}
} catch (RemoteException re) {
@@ -6034,7 +6034,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- Preconditions.checkStringNotEmpty(wipeReasonForUser, "wipeReasonForUser is null or empty");
enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
final ActiveAdmin admin;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 9d09f5c44a28..0e8200992a14 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -439,6 +439,10 @@ public class ActivityTestsBase {
}
@Override
+ void updateUsageStats(ActivityRecord component, boolean resumed) {
+ }
+
+ @Override
final protected ActivityStackSupervisor createStackSupervisor() {
final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
final KeyguardController keyguardController = mock(KeyguardController.class);
@@ -497,10 +501,6 @@ public class ActivityTestsBase {
}
@Override
- void updateUsageStats(ActivityRecord component, boolean resumed) {
- }
-
- @Override
Configuration getGlobalConfiguration() {
return mContext.getResources().getConfiguration();
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index b238e4376b1d..d34f951ffd61 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -30,7 +30,7 @@ import com.android.server.wm.utils.WmDisplayCutout;
public class FakeWindowState implements WindowManagerPolicy.WindowState {
- private WindowFrames windowFrames;
+ private WindowFrames mWindowFrames = new WindowFrames();
public WindowManager.LayoutParams attrs;
public int displayId;
@@ -53,41 +53,40 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState {
}
@Override
- public void computeFrameLw(WindowFrames windowFrames) {
- this.windowFrames = windowFrames;
+ public void computeFrameLw() {
}
@Override
public Rect getFrameLw() {
- return windowFrames.mParentFrame;
+ return mWindowFrames.mParentFrame;
}
@Override
public Rect getDisplayFrameLw() {
- return windowFrames.mDisplayFrame;
+ return mWindowFrames.mDisplayFrame;
}
@Override
public Rect getOverscanFrameLw() {
- return windowFrames.mOverscanFrame;
+ return mWindowFrames.mOverscanFrame;
}
@Override
public Rect getContentFrameLw() {
- return windowFrames.mContentFrame;
+ return mWindowFrames.mContentFrame;
}
@Override
public Rect getVisibleFrameLw() {
- return windowFrames.mVisibleFrame;
+ return mWindowFrames.mVisibleFrame;
}
public Rect getStableFrame() {
- return windowFrames.mStableFrame;
+ return mWindowFrames.mStableFrame;
}
public Rect getDecorFrame() {
- return windowFrames.mDecorFrame;
+ return mWindowFrames.mDecorFrame;
}
@Override
@@ -252,6 +251,11 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState {
}
@Override
+ public WindowFrames getWindowFrames() {
+ return mWindowFrames;
+ }
+
+ @Override
public boolean isInputMethodTarget() {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index e64823085d35..088672973524 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -202,8 +202,8 @@ public class WindowFrameTests extends WindowTestsBase {
// When mFrame extends past cf, the content insets are
// the difference between mFrame and ContentFrame. Visible
// and stable frames work the same way.
- final WindowFrames windowFrames = new WindowFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+ w.computeFrameLw();
assertFrame(w, 0, 0, 1000, 1000);
assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
assertVisibleInset(w, 0, topVisibleInset, 0, bottomVisibleInset);
@@ -217,7 +217,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
w.mRequestedWidth = 100;
w.mRequestedHeight = 100;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 100, 100, 200, 200);
assertContentInset(w, 0, 0, 0, 0);
// In this case the frames are shrunk to the window frame.
@@ -238,8 +238,8 @@ public class WindowFrameTests extends WindowTestsBase {
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
- final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, pf);
- w.computeFrameLw(windowFrames);
+ w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw();
assertFrame(w, 0, 0, 1000, 1000);
// It can select various widths and heights within the bounds.
@@ -247,14 +247,14 @@ public class WindowFrameTests extends WindowTestsBase {
// and we use mRequestedWidth/mRequestedHeight
w.mAttrs.width = 300;
w.mAttrs.height = 300;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
// Explicit width and height without requested width/height
// gets us nothing.
assertFrame(w, 0, 0, 0, 0);
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
// With requestedWidth/Height we can freely choose our size within the
// parent bounds.
assertFrame(w, 0, 0, 300, 300);
@@ -267,14 +267,14 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = -1;
w.mAttrs.width = 100;
w.mAttrs.height = 100;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 0, 0, 100, 100);
w.mAttrs.flags = 0;
// But sizes too large will be clipped to the containing frame
w.mRequestedWidth = 1200;
w.mRequestedHeight = 1200;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 0, 0, 1000, 1000);
// Before they are clipped though windows will be shifted
@@ -282,7 +282,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.y = 300;
w.mRequestedWidth = 1000;
w.mRequestedHeight = 1000;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 0, 0, 1000, 1000);
// If there is room to move around in the parent frame the window will be shifted according
@@ -292,16 +292,16 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 700, 0, 1000, 300);
w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 700, 700, 1000, 1000);
// Window specified x and y are interpreted as offsets in the opposite
// direction of gravity
w.mAttrs.x = 100;
w.mAttrs.y = 100;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, 600, 600, 900, 900);
}
@@ -322,8 +322,9 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
- final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ final WindowFrames windowFrames = w.getWindowFrames();
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+ w.computeFrameLw();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -336,7 +337,7 @@ public class WindowFrameTests extends WindowTestsBase {
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
int contentInsetRight = taskRight - cfRight;
int contentInsetBottom = taskBottom - cfBottom;
@@ -354,7 +355,7 @@ public class WindowFrameTests extends WindowTestsBase {
final int insetBottom = insetTop + (taskBottom - taskTop);
task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom);
windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
contentInsetRight = insetRight - cfRight;
contentInsetBottom = insetBottom - cfBottom;
@@ -384,13 +385,14 @@ public class WindowFrameTests extends WindowTestsBase {
// We use a decor content frame with insets to produce cropping.
Rect dcf = new Rect(cf);
- final WindowFrames windowFrames = new WindowFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ final WindowFrames windowFrames = w.getWindowFrames();
+ windowFrames.setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+ w.computeFrameLw();
assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
windowFrames.mDecorFrame.setEmpty();
// Likewise with no decor frame we would get no crop
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
// Now we set up a window which doesn't fill the entire decor frame.
@@ -404,7 +406,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.height = logicalHeight / 2;
w.mRequestedWidth = logicalWidth / 2;
w.mRequestedHeight = logicalHeight / 2;
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
// Normally the crop is shrunk from the decor frame
// to the computed window frame.
@@ -437,8 +439,9 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
- final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ final WindowFrames windowFrames = w.getWindowFrames();
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+ w.computeFrameLw();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -455,7 +458,7 @@ public class WindowFrameTests extends WindowTestsBase {
pf.set(0, 0, logicalWidth, logicalHeight);
task.mFullscreenForTest = true;
windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
assertContentFrame(w, cf);
assertContentInset(w, 0, 0, 0, 0);
@@ -473,9 +476,10 @@ public class WindowFrameTests extends WindowTestsBase {
final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height());
- final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ final WindowFrames windowFrames = w.getWindowFrames();
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
windowFrames.setDisplayCutout(cutout);
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
@@ -497,9 +501,10 @@ public class WindowFrameTests extends WindowTestsBase {
final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height());
- final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ final WindowFrames windowFrames = w.getWindowFrames();
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
windowFrames.setDisplayCutout(cutout);
- w.computeFrameLw(windowFrames);
+ w.computeFrameLw();
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index b43d9a671751..6af3ea763c13 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -391,14 +391,14 @@ public class WindowStateTests extends WindowTestsBase {
@Test
public void testDisplayCutoutIsCalculatedRelativeToFrame() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- WindowFrames wf = new WindowFrames();
+ WindowFrames wf = app.getWindowFrames();
wf.mParentFrame.set(7, 10, 185, 380);
wf.mDisplayFrame.set(wf.mParentFrame);
final DisplayCutout cutout = new DisplayCutout(new Rect(0, 15, 0, 22),
Arrays.asList(new Rect(95, 0, 105, 15), new Rect(95, 378, 105, 400)));
wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400)));
- app.computeFrameLw(wf);
+ app.computeFrameLw();
assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 91f4bc837eaa..702161e48b75 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -45,6 +45,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
@@ -60,6 +61,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Xml;
import com.android.internal.R;
@@ -74,12 +76,16 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -88,7 +94,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ConditionProviders mConditionProviders;
@Mock NotificationManager mNotificationManager;
- @Mock private Resources mResources;
+ private Resources mResources;
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelperSpy;
private Context mContext;
@@ -101,11 +107,17 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mTestableLooper = TestableLooper.get(this);
mContext = spy(getContext());
mContentResolver = mContext.getContentResolver();
- when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getString(R.string.zen_mode_default_every_night_name)).thenReturn("night");
- when(mResources.getString(R.string.zen_mode_default_events_name)).thenReturn("events");
- when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
+ mResources = spy(mContext.getResources());
+ try {
+ when(mResources.getXml(R.xml.default_zen_mode_config)).thenReturn(
+ getDefaultConfigParser());
+ } catch (Exception e) {
+ Log.d("ZenModeHelperTest", "Couldn't mock default zen mode config xml file err=" +
+ e.toString());
+ }
+
+ when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
mConditionProviders = new ConditionProviders(mContext, new UserProfiles(),
AppGlobals.getPackageManager());
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
@@ -113,6 +125,30 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mConditionProviders));
}
+ private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
+ String xml = "<zen version=\"8\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"true\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<automatic ruleId=\"EVENTS_DEFAULT_RULE\" enabled=\"false\" snoozing=\"false\""
+ + " name=\"Event\" zen=\"1\""
+ + " component=\"android/com.android.server.notification.EventConditionProvider\""
+ + " conditionId=\"condition://android/event?userId=-10000&amp;calendar=&amp;"
+ + "reply=1\"/>\n"
+ + "<automatic ruleId=\"EVERY_NIGHT_DEFAULT_RULE\" enabled=\"false\""
+ + " snoozing=\"false\" name=\"Sleeping\" zen=\"1\""
+ + " component=\"android/com.android.server.notification.ScheduleConditionProvider\""
+ + " conditionId=\"condition://android/schedule?days=1.2.3.4.5.6.7 &amp;start=22.0"
+ + "&amp;end=7.0&amp;exitAtAlarm=true\"/>"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ return new XmlResourceParserImpl(parser);
+ }
+
private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup, Integer version)
throws Exception {
XmlSerializer serializer = new FastXmlSerializer();
@@ -649,8 +685,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.id = "customRule";
customRule.name = "Custom Rule";
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- customRule.component = new ComponentName("test", "test");
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
automaticRules.put("customRule", customRule);
mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
@@ -662,8 +698,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
mZenModeHelperSpy.readXml(parser, true);
- assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode());
assertEquals(original, mZenModeHelperSpy.mConfig);
+ assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode());
}
@Test
@@ -678,6 +714,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.name = "Custom Rule";
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
enabledAutoRule.put("customRule", customRule);
mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule;
@@ -842,6 +879,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.name = "Custom Rule";
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
disabledAutoRule.put("customRule", customRule);
mZenModeHelperSpy.mConfig.automaticRules = disabledAutoRule;
@@ -877,6 +915,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.name = "Custom Rule";
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
automaticRules.put("customRule", customRule);
ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
@@ -886,6 +925,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
defaultScheduleRuleInfo);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
automaticRules.put(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, defaultScheduleRule);
@@ -922,6 +962,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.name = "Custom Rule";
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
automaticRules.put("customRule", customRule);
ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
@@ -1015,4 +1056,294 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers);
assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
}
+
+ /**
+ * Wrapper to use XmlPullParser as XmlResourceParser for Resources.getXml()
+ */
+ final class XmlResourceParserImpl implements XmlResourceParser {
+ private XmlPullParser parser;
+
+ public XmlResourceParserImpl(XmlPullParser parser) {
+ this.parser = parser;
+ }
+
+ public int getEventType() throws XmlPullParserException {
+ return parser.getEventType();
+ }
+
+ @Override
+ public void setFeature(String name, boolean state) throws XmlPullParserException {
+ parser.setFeature(name, state);
+ }
+
+ @Override
+ public boolean getFeature(String name) {
+ return false;
+ }
+
+ @Override
+ public void setProperty(String name, Object value) throws XmlPullParserException {
+ parser.setProperty(name, value);
+ }
+
+ @Override
+ public Object getProperty(String name) {
+ return parser.getProperty(name);
+ }
+
+ @Override
+ public void setInput(Reader in) throws XmlPullParserException {
+ parser.setInput(in);
+ }
+
+ @Override
+ public void setInput(InputStream inputStream, String inputEncoding)
+ throws XmlPullParserException {
+ parser.setInput(inputStream, inputEncoding);
+ }
+
+ @Override
+ public String getInputEncoding() {
+ return parser.getInputEncoding();
+ }
+
+ @Override
+ public void defineEntityReplacementText(String entityName, String replacementText)
+ throws XmlPullParserException {
+ parser.defineEntityReplacementText(entityName, replacementText);
+ }
+
+ @Override
+ public int getNamespaceCount(int depth) throws XmlPullParserException {
+ return parser.getNamespaceCount(depth);
+ }
+
+ @Override
+ public String getNamespacePrefix(int pos) throws XmlPullParserException {
+ return parser.getNamespacePrefix(pos);
+ }
+
+ @Override
+ public String getNamespaceUri(int pos) throws XmlPullParserException {
+ return parser.getNamespaceUri(pos);
+ }
+
+ @Override
+ public String getNamespace(String prefix) {
+ return parser.getNamespace(prefix);
+ }
+
+ @Override
+ public int getDepth() {
+ return parser.getDepth();
+ }
+
+ @Override
+ public String getPositionDescription() {
+ return parser.getPositionDescription();
+ }
+
+ @Override
+ public int getLineNumber() {
+ return parser.getLineNumber();
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return parser.getColumnNumber();
+ }
+
+ @Override
+ public boolean isWhitespace() throws XmlPullParserException {
+ return parser.isWhitespace();
+ }
+
+ @Override
+ public String getText() {
+ return parser.getText();
+ }
+
+ @Override
+ public char[] getTextCharacters(int[] holderForStartAndLength) {
+ return parser.getTextCharacters(holderForStartAndLength);
+ }
+
+ @Override
+ public String getNamespace() {
+ return parser.getNamespace();
+ }
+
+ @Override
+ public String getName() {
+ return parser.getName();
+ }
+
+ @Override
+ public String getPrefix() {
+ return parser.getPrefix();
+ }
+
+ @Override
+ public boolean isEmptyElementTag() throws XmlPullParserException {
+ return false;
+ }
+
+ @Override
+ public int getAttributeCount() {
+ return parser.getAttributeCount();
+ }
+
+ public int next() throws IOException, XmlPullParserException {
+ return parser.next();
+ }
+
+ @Override
+ public int nextToken() throws XmlPullParserException, IOException {
+ return parser.next();
+ }
+
+ @Override
+ public void require(int type, String namespace, String name)
+ throws XmlPullParserException, IOException {
+ parser.require(type, namespace, name);
+ }
+
+ @Override
+ public String nextText() throws XmlPullParserException, IOException {
+ return parser.nextText();
+ }
+
+ @Override
+ public String getAttributeNamespace(int index) {
+ return "";
+ }
+
+ @Override
+ public String getAttributeName(int index) {
+ return parser.getAttributeName(index);
+ }
+
+ @Override
+ public String getAttributePrefix(int index) {
+ return parser.getAttributePrefix(index);
+ }
+
+ @Override
+ public String getAttributeType(int index) {
+ return parser.getAttributeType(index);
+ }
+
+ @Override
+ public boolean isAttributeDefault(int index) {
+ return parser.isAttributeDefault(index);
+ }
+
+ @Override
+ public String getAttributeValue(int index) {
+ return parser.getAttributeValue(index);
+ }
+
+ @Override
+ public String getAttributeValue(String namespace, String name) {
+ return parser.getAttributeValue(namespace, name);
+ }
+
+ @Override
+ public int getAttributeNameResource(int index) {
+ return 0;
+ }
+
+ @Override
+ public int getAttributeListValue(String namespace, String attribute, String[] options,
+ int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public boolean getAttributeBooleanValue(String namespace, String attribute,
+ boolean defaultValue) {
+ return false;
+ }
+
+ @Override
+ public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public int getAttributeUnsignedIntValue(String namespace, String attribute,
+ int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public float getAttributeFloatValue(String namespace, String attribute,
+ float defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public int getAttributeListValue(int index, String[] options, int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
+ return false;
+ }
+
+ @Override
+ public int getAttributeResourceValue(int index, int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public int getAttributeIntValue(int index, int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public int getAttributeUnsignedIntValue(int index, int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public float getAttributeFloatValue(int index, float defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public String getIdAttribute() {
+ return null;
+ }
+
+ @Override
+ public String getClassAttribute() {
+ return null;
+ }
+
+ @Override
+ public int getIdAttributeResourceValue(int defaultValue) {
+ return 0;
+ }
+
+ @Override
+ public int getStyleAttribute() {
+ return 0;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public int nextTag() throws IOException, XmlPullParserException {
+ return parser.nextTag();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 91e24a955013..e40bae18d4f0 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -603,7 +603,7 @@ public class SmsMessage {
/**
* Returns the message body as a String, if it exists and is text based.
- * @return message body is there is one, otherwise null
+ * @return message body if there is one, otherwise null
*/
public String getMessageBody() {
return mWrappedSmsMessage.getMessageBody();
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index e9423f75c9e1..777b850bc9c5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -86,9 +86,8 @@ public class SubscriptionManager {
/** @hide */
public static final int INVALID_PHONE_INDEX = -1;
- /** An invalid slot identifier */
- /** @hide */
- public static final int INVALID_SIM_SLOT_INDEX = -1;
+ /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
+ public static final int INVALID_SIM_SLOT_INDEX = -2;
/** Indicates the caller wants the default sub id. */
/** @hide */
@@ -139,9 +138,8 @@ public class SubscriptionManager {
/** @hide */
public static final String SIM_SLOT_INDEX = "sim_id";
- /** SIM is not inserted */
- /** @hide */
- public static final int SIM_NOT_INSERTED = -1;
+ /** Indicates SIM is not inserted. This can be returned by {@link #getSlotIndex(int)}. */
+ public static final int SIM_NOT_INSERTED = -3;
/**
* TelephonyProvider column name for user displayed name.
@@ -1264,16 +1262,22 @@ public class SubscriptionManager {
/**
* Get slotIndex associated with the subscription.
- * @return slotIndex as a positive integer or a negative value if an error either
- * SIM_NOT_INSERTED or < 0 if an invalid slot index
- * @hide
- */
- @UnsupportedAppUsage
- public static int getSlotIndex(int subId) {
- if (!isValidSubscriptionId(subId)) {
+ *
+ * @param subscriptionId the unique SubscriptionInfo index in database
+ * @return slotIndex as a positive integer or a negative value,
+ * <ol>
+ * <li>{@link #INVALID_SUBSCRIPTION_ID} if the supplied subscriptionId is invalid </li>
+ * <li>{@link #SIM_NOT_INSERTED} if sim is not inserted </li>
+ * <li>{@link #INVALID_SIM_SLOT_INDEX} if the supplied subscriptionId doesn't have an
+ * associated slot index </li>
+ * </ol>
+ */
+ public static int getSlotIndex(int subscriptionId) {
+ if (!isValidSubscriptionId(subscriptionId)) {
if (DBG) {
- logd("[getSlotIndex]- fail");
+ logd("[getSlotIndex]- supplied subscriptionId is invalid. ");
}
+ return INVALID_SUBSCRIPTION_ID;
}
int result = INVALID_SIM_SLOT_INDEX;
@@ -1281,7 +1285,7 @@ public class SubscriptionManager {
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- result = iSub.getSlotIndex(subId);
+ result = iSub.getSlotIndex(subscriptionId);
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b5d1f0658edd..a8bcbe33966a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -69,6 +69,7 @@ import com.android.internal.telephony.IAnas;
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyProperties;
@@ -5789,21 +5790,46 @@ public class TelephonyManager {
* @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
* normal network selection next time.
- * @return true on success; false on any failure.
+ * @return {@code true} on success; {@code false} on any failure.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
+ return setNetworkSelectionModeManual(
+ new OperatorInfo(
+ "" /* operatorAlphaLong */, "" /* operatorAlphaShort */, operatorNumeric),
+ persistSelection);
+ }
+
+ /**
+ * Ask the radio to connect to the input network and change selection mode to manual.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @param operatorInfo included the PLMN id, long name, short name of the operator to attach to.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
+ * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
+ * normal network selection next time.
+ * @return {@code true} on success; {@code true} on any failure.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setNetworkSelectionModeManual(
+ OperatorInfo operatorInfo, boolean persistSelection) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.setNetworkSelectionModeManual(
- getSubId(), operatorNumeric, persistSelection);
+ getSubId(), operatorInfo, persistSelection);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "setNetworkSelectionModeManual NPE", ex);
}
return false;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c0bccde2cda3..afb1d82b5e9f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -865,14 +865,15 @@ interface ITelephony {
* Ask the radio to connect to the input network and change selection mode to manual.
*
* @param subId the id of the subscription.
- * @param operatorNumeric the PLMN of the operator to attach to.
- * @param persistSelection Whether the selection will persist until reboot. If true, only allows
+ * @param operatorInfo the operator inforamtion, included the PLMN, long name and short name of
+ * the operator to attach to.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
* normal network selection next time.
- * @return true if the request suceeded.
+ * @return {@code true} on success; {@code true} on any failure.
*/
- boolean setNetworkSelectionModeManual(int subId, in String operatorNumeric,
- boolean persistSelection);
+ boolean setNetworkSelectionModeManual(
+ int subId, in OperatorInfo operatorInfo, boolean persisSelection);
/**
* Set the preferred network type.
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index d0245a0a07b4..a47e2b026021 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -21,7 +21,7 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * {@hide}
+ * @hide
*/
public class OperatorInfo implements Parcelable {
public enum State {
diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk
deleted file mode 100644
index a8f5b0867c65..000000000000
--- a/tests/ImfTest/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ImfTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
deleted file mode 100644
index 82dbe753534c..000000000000
--- a/tests/ImfTest/AndroidManifest.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.imftest">
-
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
- <application>
-
- <activity android:name=".samples.InputTypeActivity" android:label="Input Type Activity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ButtonActivity" android:label="Button Activity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ManyEditTextActivityNoScrollPanScan" android:label="ManyEditTextActivityNoScrollPanScan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ManyEditTextActivityScrollPanScan" android:label="ManyEditTextActivityScrollPanScan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ManyEditTextActivityScrollResize" android:label="ManyEditTextActivityScrollResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BottomEditTextActivityPanScan" android:label="BottomEditTextActivityPanScan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BottomEditTextActivityResize" android:label="BottomEditTextActivityResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.OneEditTextActivitySelected" android:label="OneEditTextActivitySelected">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.OneEditTextActivityNotSelected" android:label="OneEditTextActivityNotSelected">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.AutoCompleteTextViewActivityPortrait" android:label="AutoCompleteTextViewActivityPortrait" android:screenOrientation="portrait">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.AutoCompleteTextViewActivityLandscape" android:label="AutoCompleteTextViewActivityLandscape" android:screenOrientation="landscape">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- </application>
-
-</manifest>
diff --git a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
deleted file mode 100644
index 1a2b7eb0407e..000000000000
--- a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="20dip"
- android:orientation="vertical">
-
- <View
- android:id="@+id/blank"
- android:layout_height="0dip"
- android:layout_width="match_parent"
- android:layout_weight="1"/>
-
- <EditText
- android:id="@+id/dialog_edit_text"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:scrollHorizontally="true"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</LinearLayout>
diff --git a/tests/ImfTest/res/layout/full_screen_edit_text.xml b/tests/ImfTest/res/layout/full_screen_edit_text.xml
deleted file mode 100644
index e760ac181245..000000000000
--- a/tests/ImfTest/res/layout/full_screen_edit_text.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** 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.
-*/
--->
-
-<EditText xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/data"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:minLines="15"
- android:gravity="top"/>
-
diff --git a/tests/ImfTest/res/layout/one_edit_text_activity.xml b/tests/ImfTest/res/layout/one_edit_text_activity.xml
deleted file mode 100644
index 055822823bf5..000000000000
--- a/tests/ImfTest/res/layout/one_edit_text_activity.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:baselineAligned="false">
-
- <View android:id="@+id/blank"
- android:layout_height="0dip"
- android:layout_width="match_parent"
- android:layout_weight="1"
- />
-
- <EditText android:id="@+id/dialog_edit_text"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:scrollHorizontally="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="@android:drawable/divider_horizontal_dark"
- />
-</LinearLayout>
diff --git a/tests/ImfTest/res/layout/sample_edit_text.xml b/tests/ImfTest/res/layout/sample_edit_text.xml
deleted file mode 100644
index 3ff676727662..000000000000
--- a/tests/ImfTest/res/layout/sample_edit_text.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:gravity="center_vertical"
- >
-
- <TextView android:id="@+id/label"
- android:layout_width="100dip"
- android:layout_height="wrap_content"
- android:gravity="right|center_vertical"
- />
-
- <EditText android:id="@+id/data"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
- />
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="@android:drawable/divider_horizontal_dark"
- />
-</LinearLayout>
diff --git a/tests/ImfTest/res/values/config.xml b/tests/ImfTest/res/values/config.xml
deleted file mode 100644
index 5ae40a381523..000000000000
--- a/tests/ImfTest/res/values/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 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.
- */
--->
-<resources>
- <bool name="def_expect_ime_autopop">false</bool>
-</resources>
diff --git a/tests/ImfTest/res/values/strings.xml b/tests/ImfTest/res/values/strings.xml
deleted file mode 100644
index fc87480788d6..000000000000
--- a/tests/ImfTest/res/values/strings.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Strings for sample activities -->
- <string name="normal_edit_text_label">Normal</string>
- <string name="uri_edit_text_label">Uri</string>
- <string name="email_address_edit_text_label">Email Address</string>
- <string name="email_subject_edit_text_label">Email Subject</string>
- <string name="email_content_edit_text_label">Email Content</string>
- <string name="person_name_edit_text_label">Person Name</string>
- <string name="postal_address_edit_text_label">Postal Address</string>
- <string name="password_edit_text_label">Password</string>
- <string name="search_string_edit_text_label">Search String</string>
- <string name="web_edit_text_label">Web Edit Text</string>
- <string name="signed_number_edit_text_label">Signed Number</string>
- <string name="decimal_number_edit_text_label">Decimal Number</string>
- <string name="phone_number_edit_text_label">Phone Number</string>
- <string name="normal_datetime_edit_text_label">Datetime</string>
- <string name="date_edit_text_label">Date</string>
- <string name="time_edit_text_label">Time</string>
- <string name="cap_chars_edit_text_label">Cap Chars</string>
- <string name="cap_words_edit_text_label">Cap Words</string>
- <string name="multiline_edit_text_label">Multiline</string>
- <string name="search_edit_text_label">Search (flag)</string>
- <string name="cap_sentences_edit_text_label">Cap Sentences</string>
- <string name="auto_complete_edit_text_label">Auto Complete</string>
- <string name="auto_correct_edit_text_label">Auto Correct</string>
- <string name="test_dialog">Test Dialog</string>
- <string name="open_dialog_scrollable">open scrollable dialog</string>
- <string name="open_dialog_nonscrollable">open nonscrollable dialog</string>
-
-
-</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
deleted file mode 100644
index 6115fd5a0fd0..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.provider.MediaStore;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ArrayAdapter;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-
-import com.android.internal.R;
-
-/*
- * Activity with AutoCompleteTextView forced to landscape mode
- */
-public class AutoCompleteTextViewActivityLandscape extends Activity
-{
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.auto_complete_list);
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_dropdown_item_1line, COUNTRIES);
- AutoCompleteTextView textView = findViewById(R.id.edit);
- textView.setAdapter(adapter);
- }
-
- static final String[] COUNTRIES = new String[] {
- "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
- "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
- "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
- "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
- "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
- "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
- "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
- "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
- "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
- "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
- "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
- "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
- "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
- "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
- "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
- "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
- "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
- "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
- "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
- "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
- "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
- "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
- "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
- "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
- "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
- "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
- "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
- "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
- "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
- "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
- "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
- "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
- "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
- "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
- "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
- "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
- "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
- "Ukraine", "United Arab Emirates", "United Kingdom",
- "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
- "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
- "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
- };
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
deleted file mode 100644
index 253c50fe5810..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ArrayAdapter;
-
-import com.android.internal.R;
-
-/*
- * Activity with AutoCompleteTextView (Candidate bar should not appear)
- */
-public class AutoCompleteTextViewActivityPortrait extends Activity
-{
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.auto_complete_list);
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_dropdown_item_1line, COUNTRIES);
- AutoCompleteTextView textView = findViewById(R.id.edit);
- textView.setAdapter(adapter);
- }
-
- static final String[] COUNTRIES = new String[] {
- "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
- "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
- "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
- "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
- "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
- "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
- "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
- "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
- "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
- "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
- "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
- "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
- "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
- "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
- "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
- "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
- "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
- "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
- "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
- "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
- "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
- "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
- "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
- "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
- "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
- "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
- "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
- "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
- "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
- "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
- "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
- "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
- "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
- "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
- "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
- "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
- "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
- "Ukraine", "United Arab Emirates", "United Kingdom",
- "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
- "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
- "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
- };
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
deleted file mode 100644
index 033082fbab42..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-public class BigEditTextActivityNonScrollablePanScan extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
-
- ((LinearLayout) mRootView).addView(view);
-
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
deleted file mode 100644
index 8a16deab9a40..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-public class BigEditTextActivityNonScrollableResize extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
-
- ((LinearLayout) mRootView).addView(view);
-
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
deleted file mode 100644
index b4fdc4c07584..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class BigEditTextActivityScrollablePanScan extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
- private LinearLayout mLayout;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-
- mRootView = new ScrollView(this);
- ((ScrollView) mRootView).setFillViewport(true);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
-
- mLayout.addView(view);
-
- ((ScrollView) mRootView).addView(mLayout);
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
deleted file mode 100644
index 757b6b5d57ce..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class BigEditTextActivityScrollableResize extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
- private LinearLayout mLayout;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-
- mRootView = new ScrollView(this);
- ((ScrollView) mRootView).setFillViewport(true);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
-
- mLayout.addView(view);
-
- ((ScrollView) mRootView).addView(mLayout);
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
deleted file mode 100644
index 91a329d25f90..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.imftest.R;
-
-/*
- * Activity with EditText at the bottom (Pan&Scan)
- */
-public class BottomEditTextActivityPanScan extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
- View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
- mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
- ((LinearLayout) mRootView).addView(view);
-
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
deleted file mode 100644
index c4c41bc7d4ee..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.imftest.R;
-
-/*
- * Activity with EditText at the bottom (Resize)
- */
-public class BottomEditTextActivityResize extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
- View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
- mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
- ((LinearLayout) mRootView).addView(view);
-
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
deleted file mode 100644
index dbaedf9f0af1..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class ButtonActivity extends Activity
-{
- static boolean mKeyboardIsActive = false;
- public static final int BUTTON_ID = 0;
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- final ButtonActivity instance = this;
-
- final Button myButton = new Button(this);
- myButton.setClickable(true);
- myButton.setText("Keyboard UP!");
- myButton.setId(BUTTON_ID);
- myButton.setFocusableInTouchMode(true);
- myButton.setOnClickListener(new View.OnClickListener()
- {
- public void onClick (View v)
- {
- InputMethodManager imm = InputMethodManager.getInstance();
- if (mKeyboardIsActive)
- {
- imm.hideSoftInputFromInputMethod(v.getWindowToken(), 0);
- myButton.setText("Keyboard UP!");
-
- }
- else
- {
- myButton.requestFocusFromTouch();
- imm.showSoftInput(v, 0);
- myButton.setText("Keyboard DOWN!");
- }
-
- mKeyboardIsActive = !mKeyboardIsActive;
- }
- });
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- layout.addView(myButton);
- setContentView(layout);
- mRootView = layout;
- }
-
- public View getRootView() {
- return mRootView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
deleted file mode 100644
index 3ed03862a04f..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.Button;
-import android.view.LayoutInflater;
-import android.app.Dialog;
-
-public class DialogActivity extends Activity {
-
- private static final int DIALOG_WITHOUT_EDITTEXT = 0;
- private static final int DIALOG_WITH_EDITTEXT = 1;
-
- private LinearLayout mLayout;
- private LayoutInflater mInflater;
- private Button mButton1;
- private Button mButton2;
- private EditText mEditText;
-
-
- @Override
- protected void onCreate(Bundle icicle)
- {
- super.onCreate(icicle);
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mButton1 = new Button(this);
- mButton1.setText("Dialog WITHOUT EditText");//(R.string.open_dialog_scrollable);
- mButton1.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- showDialog(DIALOG_WITHOUT_EDITTEXT);
- }
- });
-
- mButton2 = new Button(this);
- mButton2.setText("Dialog WITH EditText");//(R.string.open_dialog_nonscrollable);
- mButton2.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- showDialog(DIALOG_WITH_EDITTEXT);
- }
- });
-
- mEditText = new EditText(this);
- mLayout.addView(mEditText);
- mLayout.addView(mButton1);
- mLayout.addView(mButton2);
-
- setContentView(mLayout);
- }
-
- @Override
- protected Dialog onCreateDialog(int id)
- {
- switch (id)
- {
- case DIALOG_WITHOUT_EDITTEXT:
- return createDialog(false);
- case DIALOG_WITH_EDITTEXT:
- return createDialog(true);
- }
-
- return super.onCreateDialog(id);
- }
-
- protected Dialog createDialog(boolean bEditText)
- {
- LinearLayout layout;
- layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- if(bEditText)
- {
- EditText editText;
- editText = new EditText(this);
- layout.addView(editText);
- }
-
- Dialog d = new Dialog(this);
- d.setTitle("The DIALOG!!!");
- d.setCancelable(true);
- d.setContentView(layout);
- return d;
- }
-
- }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
deleted file mode 100644
index 2591b7c96ae9..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class EditTextActivityDialog extends Activity {
-
- private static final int SCROLLABLE_DIALOG_ID = 0;
- private static final int NONSCROLLABLE_DIALOG_ID = 1;
-
- private LinearLayout mLayout;
- private ScrollView mScrollView;
- private LayoutInflater mInflater;
- private Button mButton1;
- private Button mButton2;
-
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mButton1 = new Button(this);
- mButton1.setText(R.string.open_dialog_scrollable);
- mButton1.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- showDialog(SCROLLABLE_DIALOG_ID);
- }
- });
-
- mButton2 = new Button(this);
- mButton2.setText(R.string.open_dialog_nonscrollable);
- mButton2.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- showDialog(NONSCROLLABLE_DIALOG_ID);
- }
- });
-
- mLayout.addView(mButton1);
- mLayout.addView(mButton2);
-
- setContentView(mLayout);
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case SCROLLABLE_DIALOG_ID:
- return createDialog(true);
- case NONSCROLLABLE_DIALOG_ID:
- return createDialog(false);
- }
-
- return super.onCreateDialog(id);
- }
-
- protected Dialog createDialog(boolean scrollable) {
- View layout;
- EditText editText;
-
- if (scrollable) {
- layout = new ScrollView(EditTextActivityDialog.this);
- ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
-
- ((ScrollView) layout).addView((
- LinearLayout) View.inflate(EditTextActivityDialog.this,
- R.layout.dialog_edit_text_no_scroll, null));
- } else {
- layout = View.inflate(EditTextActivityDialog.this,
- R.layout.dialog_edit_text_no_scroll, null);
- }
-
- Dialog d = new Dialog(EditTextActivityDialog.this);
- d.setTitle(getString(R.string.test_dialog));
- d.setCancelable(true);
- d.setContentView(layout);
- return d;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
deleted file mode 100644
index 299e6bb2778e..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-
-public class InputTypeActivity extends Activity {
-
- private LinearLayout mLayout;
- private ScrollView mScrollView;
- private LayoutInflater mInflater;
- private ViewGroup mParent;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mScrollView = new ScrollView(this);
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mInflater = getLayoutInflater();
- mParent = mLayout;
-
- /* Normal Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL,
- R.string.normal_edit_text_label));
-
- /* Normal Edit Text w/Cap Chars Flag*/
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS,
- R.string.cap_chars_edit_text_label));
-
- /* Normal Edit Text w/Cap Words Flag*/
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS,
- R.string.cap_words_edit_text_label));
-
- /* Normal Edit Text w/Cap Multiline Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE,
- R.string.multiline_edit_text_label));
-
- /* Normal Edit Text w/Cap Sentences Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES,
- R.string.cap_sentences_edit_text_label));
-
- /* Normal Edit Text w/Auto-complete Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE,
- R.string.auto_complete_edit_text_label));
-
- /* Normal Edit Text w/Auto-correct Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT,
- R.string.auto_correct_edit_text_label));
-
- /* Uri Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI,
- R.string.uri_edit_text_label));
-
- /* Email Address Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
- R.string.email_address_edit_text_label));
-
- /* Email Subject Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
- R.string.email_subject_edit_text_label));
-
- /* Email Content Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE,
- R.string.email_content_edit_text_label));
-
- /* Person Name Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME,
- R.string.person_name_edit_text_label));
-
- /* Postal Address Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
- R.string.postal_address_edit_text_label));
-
- /* Password Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD,
- R.string.password_edit_text_label));
-
- /* Web Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT,
- R.string.web_edit_text_label));
-
- /* Signed Number Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_SIGNED,
- R.string.signed_number_edit_text_label));
-
- /* Decimal Number Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_DECIMAL,
- R.string.decimal_number_edit_text_label));
-
- /* Phone Number Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_PHONE,
- R.string.phone_number_edit_text_label));
-
- /* Normal Datetime Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_NORMAL,
- R.string.normal_datetime_edit_text_label));
-
- /* Date Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_DATE,
- R.string.date_edit_text_label));
-
- /* Time Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_TIME,
- R.string.time_edit_text_label));
-
- mScrollView.addView(mLayout);
- setContentView(mScrollView);
- }
-
- private View buildEntryView(int inputType, int label) {
-
-
- View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false);
-
- EditText editText = (EditText) view.findViewById(R.id.data);
- editText.setInputType(inputType);
-
- TextView textView = (TextView) view.findViewById(R.id.label);
- textView.setText(label);
-
- return view;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
deleted file mode 100644
index 646e4805f32e..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Full screen of EditTexts (Non-Scrollable, Pan&Scan)
- */
-public class ManyEditTextActivityNoScrollPanScan extends Activity
-{
- public static final int NUM_EDIT_TEXTS = 9;
-
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
- for (int i=0; i<NUM_EDIT_TEXTS; i++)
- {
- final EditText editText = new EditText(this);
- editText.setText(String.valueOf(i));
- editText.setId(i);
- ((LinearLayout) mRootView).addView(editText);
- }
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
deleted file mode 100644
index 0387e1ec5d13..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Full screen of EditTexts (Scrollable, Pan&Scan)
- */
-public class ManyEditTextActivityScrollPanScan extends Activity
-{
- public static final int NUM_EDIT_TEXTS = 12;
-
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- mRootView = new ScrollView(this);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- for (int i=0; i<NUM_EDIT_TEXTS; i++)
- {
- final EditText editText = new EditText(this);
- editText.setText(String.valueOf(i));
- editText.setId(i);
- layout.addView(editText);
- }
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
deleted file mode 100644
index 7793b553d746..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-
-/*
- * Full screen of EditTexts (Scrollable, Resize)
- */
-public class ManyEditTextActivityScrollResize extends Activity
-{
- public static final int NUM_EDIT_TEXTS = 12;
-
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- mRootView = new ScrollView(this);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- for (int i=0; i<NUM_EDIT_TEXTS; i++)
- {
- final EditText editText = new EditText(this);
- editText.setText(String.valueOf(i));
- editText.setId(i);
- layout.addView(editText);
- }
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
deleted file mode 100644
index c4be21c7f2d8..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Debug;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Activity with non-EditText view selected initially
- */
-public class OneEditTextActivityNotSelected extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- mRootView = new ScrollView(this);
-
- EditText editText = new EditText(this);
- Button button = new Button(this);
- button.setText("The focus is here.");
- button.setFocusableInTouchMode(true);
- button.requestFocus();
- mDefaultFocusedView = button;
- layout.addView(button);
- layout.addView(editText);
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
deleted file mode 100644
index 64882aa30eb1..000000000000
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Activity with EditText selected initially
- */
-public class OneEditTextActivitySelected extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- mRootView = new ScrollView(this);
-
- EditText editText = new EditText(this);
- editText.requestFocus();
- mDefaultFocusedView = editText;
- layout.addView(editText);
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
-
- // set to resize so IME is always shown (and also so
- // ImfBaseTestCase#destructiveCheckImeInitialState thinks it should always be shown
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
deleted file mode 100644
index 14186d7a5a87..000000000000
--- a/tests/ImfTest/tests/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_PACKAGE_NAME := ImfTestTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_INSTRUMENTATION_FOR := ImfTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
deleted file mode 100644
index c02fa0b212a5..000000000000
--- a/tests/ImfTest/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.imftest.tests">
-
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <!--
- This declares that this app uses the instrumentation test runner targeting
- the package of com.android.imftest. To run the tests use the command:
- "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
- -->
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.imftest"
- android:label="imf tests"/>
-
-</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
deleted file mode 100644
index 2db11c56e7e3..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
-
- public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
-
- public BigEditTextActivityNonScrollablePanScanTests() {
- super(BigEditTextActivityNonScrollablePanScan.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
deleted file mode 100644
index 1050794af642..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
-
- public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
-
- public BigEditTextActivityNonScrollableResizeTests() {
- super(BigEditTextActivityNonScrollableResize.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
deleted file mode 100644
index 1e848b051439..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
-
- public final String TAG = "BigEditTextActivityScrollablePanScanTests";
-
- public BigEditTextActivityScrollablePanScanTests() {
- super(BigEditTextActivityScrollablePanScan.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
deleted file mode 100644
index de607d659ebe..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
-
- public final String TAG = "BigEditTextActivityScrollableResizeTests";
-
- public BigEditTextActivityScrollableResizeTests() {
- super(BigEditTextActivityScrollableResize.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
deleted file mode 100644
index c52190552e4f..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
-
- public final String TAG = "BottomEditTextActivityPanScanTests";
-
- public BottomEditTextActivityPanScanTests() {
- super(BottomEditTextActivityPanScan.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
- View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
deleted file mode 100644
index 9a69fd509844..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
-
- public final String TAG = "BottomEditTextActivityResizeTests";
-
- public BottomEditTextActivityResizeTests() {
- super(BottomEditTextActivityResize.class);
- }
-
- @LargeTest
- public void testAppAdjustmentResize() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
- View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
deleted file mode 100644
index f6f97b517090..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.widget.Button;
-
-
-public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
-
- final public String TAG = "ButtonActivityTest";
-
- public ButtonActivityTest() {
- super(ButtonActivity.class);
- }
-
- @LargeTest
- public void testButtonActivatesIme() {
-
- final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
-
- // Push button
- // Bring the target EditText into focus.
- mTargetActivity.runOnUiThread(new Runnable() {
- public void run() {
- button.requestFocus();
- }
- });
-
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-
- // Give it a couple seconds
- pause(2000);
-
- // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
- assertTrue(mImm.isActive());
- // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
- assertFalse(mImm.isAcceptingText());
-
- destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
-
- }
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
deleted file mode 100644
index 32f80a3ad2d5..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-
-import com.android.imftest.R;
-
-public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
-
- /*
- * The amount of time we are willing to wait for the IME to appear after a user action
- * before we give up and fail the test.
- */
- public final long WAIT_FOR_IME = 5000;
-
- /*
- * Unfortunately there is now way for us to know how tall the IME is,
- * so we have to hard code a minimum and maximum value.
- */
- public final int IME_MIN_HEIGHT = 150;
- public final int IME_MAX_HEIGHT = 300;
-
- protected InputMethodManager mImm;
- protected T mTargetActivity;
- protected boolean mExpectAutoPop;
- private Class<T> mTargetActivityClass;
-
- public ImfBaseTestCase(Class<T> activityClass) {
- mTargetActivityClass = activityClass;
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- final String packageName = getInstrumentation().getTargetContext().getPackageName();
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- mTargetActivity = launchActivityWithIntent(packageName, mTargetActivityClass, intent);
- // expect ime to auto pop up if device has no hard keyboard
- int keyboardType = mTargetActivity.getResources().getConfiguration().keyboard;
- mExpectAutoPop = (keyboardType == Configuration.KEYBOARD_NOKEYS ||
- keyboardType == Configuration.KEYBOARD_UNDEFINED);
-
- mImm = InputMethodManager.getInstance();
-
- KeyguardManager keyguardManager =
- (KeyguardManager) getInstrumentation().getContext().getSystemService(
- Context.KEYGUARD_SERVICE);
- keyguardManager.newKeyguardLock("imftest").disableKeyguard();
- }
-
- // Utility test methods
- public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
-
- int[] origLocation = new int[2];
- int[] newLocation = new int[2];
-
- // Tell the keyboard to go away.
- mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
-
- // Bring the target EditText into focus.
- mTargetActivity.runOnUiThread(new Runnable() {
- public void run() {
- editText.requestFocus();
- }
- });
-
- // Get the original location of the EditText.
- editText.getLocationOnScreen(origLocation);
-
- // Tap the EditText to bring up the IME.
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-
- // Wait until the EditText pops above the IME or until we hit the timeout.
- editText.getLocationOnScreen(newLocation);
- long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
- while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
- editText.getLocationOnScreen(newLocation);
- pause(100);
- }
-
- assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
-
- // Tell the keyboard to go away.
- mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
- }
-
- public void destructiveCheckImeInitialState(View rootView, View servedView) {
- int windowSoftInputMode = mTargetActivity.getWindow().getAttributes().softInputMode;
- int adjustMode = windowSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
- if (mExpectAutoPop && adjustMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
- assertTrue(destructiveCheckImeUp(rootView, servedView));
- } else {
- assertFalse(destructiveCheckImeUp(rootView, servedView));
- }
- }
-
- public boolean destructiveCheckImeUp(View rootView, View servedView) {
- int origHeight;
- int newHeight;
-
- origHeight = rootView.getHeight();
-
- // Tell the keyboard to go away.
- mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
-
- // Give it five seconds to adjust
- newHeight = rootView.getHeight();
- long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
- while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
- newHeight = rootView.getHeight();
- }
-
- return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
- }
-
- void pause(int millis) {
- try {
- Thread.sleep(millis);
- } catch (InterruptedException e) {
- }
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
deleted file mode 100644
index 278efb1f68db..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.app.Activity;
-import android.widget.EditText;
-
-
-public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
-
- public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
- super(activityClass);
- }
-
- public abstract void testAllEditTextsAdjust();
-
- public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
-
- for (int i = 0; i < numEditTexts; i++) {
- final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
- verifyEditTextAdjustment(lastEditText, rootViewHeight);
- }
-
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
deleted file mode 100644
index 4f8d14e88ad5..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
-
- public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
-
- public ManyEditTextActivityNoScrollPanScanTests() {
- super(ManyEditTextActivityNoScrollPanScan.class);
- }
-
-
- @LargeTest
- public void testAllEditTextsAdjust() {
- verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
- mTargetActivity.getRootView().getMeasuredHeight());
- }
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
deleted file mode 100644
index 7f98f7fbdf21..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
-
- public final String TAG = "ManyEditTextActivityScrollPanScanTests";
-
-
- public ManyEditTextActivityScrollPanScanTests() {
- super(ManyEditTextActivityScrollPanScan.class);
- }
-
- @LargeTest
- public void testAllEditTextsAdjust() {
- verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
- mTargetActivity.getRootView().getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
deleted file mode 100644
index 68dae87ea5c9..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
-
- public final String TAG = "ManyEditTextActivityScrollResizeTests";
-
-
- public ManyEditTextActivityScrollResizeTests() {
- super(ManyEditTextActivityScrollResize.class);
- }
-
- @LargeTest
- public void testAllEditTextsAdjust() {
- verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
- mTargetActivity.getRootView().getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
deleted file mode 100644
index 6147d3c5c6c4..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-
-public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
-
- public final String TAG = "OneEditTextActivityNotSelectedTests";
-
- public OneEditTextActivityNotSelectedTests() {
- super(OneEditTextActivityNotSelected.class);
- }
-
- @LargeTest
- public void testSoftKeyboardNoAutoPop() {
-
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- assertFalse(mImm.isAcceptingText());
-
- View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
- View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
deleted file mode 100644
index 42fcd66f7922..000000000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.view.View;
-
-
-public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
-
- public final String TAG = "OneEditTextActivitySelectedTests";
-
- public OneEditTextActivitySelectedTests() {
- super(OneEditTextActivitySelected.class);
- }
-
- @LargeTest
- public void testSoftKeyboardAutoPop() {
-
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- assertTrue(mImm.isAcceptingText());
-
- View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
- View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tools/aapt2/development.md b/tools/aapt2/development.md
new file mode 100644
index 000000000000..8ee873a0e40f
--- /dev/null
+++ b/tools/aapt2/development.md
@@ -0,0 +1,11 @@
+# AAPT2 development
+
+## Building
+All build targets can be found in `Android.bp` file. The main ones are `make -j aapt2` and `make -j aapt2_tests`
+
+`make -j aapt2` will create an aapt2 executable in `out/host/linux-x86/bin/aapt2` (on Linux). This `aapt2` executable will then be used for all the apps in the platform.
+
+Static version of the tool (without shared libraries) can be built with `make -j static_sdk_tools dist DIST_DIR=$OUTPUT_DIRECTORY BUILD_HOST_static=1`. Note, in addition to aapt2 this command will also output other statically built tools to the `$OUTPUT_DIRECTORY`.
+
+## Running tests
+Build `make -j aapt2_tests` and then (on Linux) execute `out/host/linux-x86/nativetest64/aapt2_tests/aapt2_tests` \ No newline at end of file