summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk5
-rw-r--r--api/current.txt16
-rw-r--r--api/system-current.txt16
-rw-r--r--api/test-current.txt16
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp46
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h24
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp9
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp7
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp4
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp9
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h2
-rw-r--r--cmds/statsd/src/stats_log.proto50
-rw-r--r--cmds/statsd/src/statsd_config.proto35
-rw-r--r--core/java/android/app/ActivityManager.java11
-rw-r--r--core/java/android/app/ActivityOptions.java22
-rw-r--r--core/java/android/app/AppOpsManager.java12
-rw-r--r--core/java/android/app/IActivityManager.aidl4
-rw-r--r--core/java/android/net/OWNERS2
-rw-r--r--core/java/android/os/StrictMode.java38
-rw-r--r--core/java/android/view/IWindowManager.aidl2
-rw-r--r--core/java/com/android/internal/app/NightDisplayController.java17
-rw-r--r--core/java/com/android/internal/net/OWNERS2
-rw-r--r--core/java/com/android/internal/util/StateMachine.java2
-rw-r--r--core/res/res/values-bs/strings.xml13
-rw-r--r--core/res/res/values-in/strings.xml4
-rw-r--r--core/res/res/values-ko/strings.xml15
-rw-r--r--core/res/res/values-pl/strings.xml13
-rw-r--r--core/res/res/values-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-ta/strings.xml13
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java22
-rw-r--r--core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java4
-rw-r--r--core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java33
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java95
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java5
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java84
-rw-r--r--libs/androidfw/ResourceTypes.cpp128
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h11
-rw-r--r--libs/androidfw/tests/ConfigLocale_test.cpp42
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp73
-rw-r--r--libs/protoutil/include/android/util/ProtoOutputStream.h3
-rw-r--r--libs/protoutil/src/ProtoOutputStream.cpp14
-rw-r--r--media/java/android/media/MediaFormat.java90
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java162
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp117
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp1
-rw-r--r--packages/SettingsLib/res/drawable/ic_bt_laptop.xml26
-rw-r--r--packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml25
-rw-r--r--packages/SettingsLib/res/drawable/ic_settings_print.xml28
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml2
-rw-r--r--packages/SettingsLib/res/values/strings.xml21
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java82
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java34
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java54
-rw-r--r--packages/SystemUI/res-keyguard/values-bs/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-ko/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-pl/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-ta/strings.xml3
-rw-r--r--packages/SystemUI/res/layout/operator_name.xml31
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml5
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml10
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/DemoMode.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/RecentsComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/DockState.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java7
-rw-r--r--proto/src/metrics_constants.proto4
-rw-r--r--proto/src/wifi.proto7
-rw-r--r--services/core/java/com/android/server/BatteryService.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java224
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/net/OWNERS2
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java179
-rw-r--r--services/core/java/com/android/server/wm/DragInputEventReceiver.java151
-rw-r--r--services/core/java/com/android/server/wm/DragState.java115
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java53
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java24
-rw-r--r--services/core/java/com/android/server/wm/Session.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java129
-rw-r--r--services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java6
100 files changed, 2161 insertions, 701 deletions
diff --git a/Android.mk b/Android.mk
index 62f750c41a8b..9843f175bf2d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -989,7 +989,8 @@ framework_docs_LOCAL_DROIDDOC_SOURCE_PATH := \
framework_docs_LOCAL_INTERMEDIATE_SOURCES := \
$(framework_res_source_path)/android/R.java \
$(framework_res_source_path)/android/Manifest.java \
- $(framework_res_source_path)/com/android/internal/R.java
+ $(framework_res_source_path)/com/android/internal/R.java \
+ $(patsubst $(TARGET_OUT_COMMON_INTERMEDIATES)/%,%,$(libcore_to_document_generated))
framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
core-oj \
@@ -1060,7 +1061,7 @@ framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= \
framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES := \
frameworks/base/docs/knowntags.txt \
- libcore/Docs.mk
+ $(libcore_to_document_generated)
samples_dir := development/samples/browseable
diff --git a/api/current.txt b/api/current.txt
index 509bb88424a4..190ef220534f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22816,6 +22816,10 @@ package android.media {
field public static final java.lang.String KEY_DURATION = "durationUs";
field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
+ field public static final java.lang.String KEY_GRID_COLS = "grid-cols";
+ field public static final java.lang.String KEY_GRID_HEIGHT = "grid-height";
+ field public static final java.lang.String KEY_GRID_ROWS = "grid-rows";
+ field public static final java.lang.String KEY_GRID_WIDTH = "grid-width";
field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
field public static final java.lang.String KEY_HEIGHT = "height";
field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
@@ -22859,6 +22863,7 @@ package android.media {
field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+ field public static final java.lang.String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
@@ -22951,9 +22956,13 @@ package android.media {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
method public byte[] getEmbeddedPicture();
+ method public android.graphics.Bitmap getFrameAtIndex(int);
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
+ method public android.graphics.Bitmap[] getFramesAtIndex(int, int);
+ method public android.graphics.Bitmap getImageAtIndex(int);
+ method public android.graphics.Bitmap getPrimaryImage();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
@@ -22976,11 +22985,18 @@ package android.media {
field public static final int METADATA_KEY_DURATION = 9; // 0x9
field public static final int METADATA_KEY_GENRE = 6; // 0x6
field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
+ field public static final int METADATA_KEY_HAS_IMAGE = 26; // 0x1a
field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+ field public static final int METADATA_KEY_IMAGE_COUNT = 27; // 0x1b
+ field public static final int METADATA_KEY_IMAGE_HEIGHT = 30; // 0x1e
+ field public static final int METADATA_KEY_IMAGE_PRIMARY = 28; // 0x1c
+ field public static final int METADATA_KEY_IMAGE_ROTATION = 31; // 0x1f
+ field public static final int METADATA_KEY_IMAGE_WIDTH = 29; // 0x1d
field public static final int METADATA_KEY_LOCATION = 23; // 0x17
field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
field public static final int METADATA_KEY_TITLE = 7; // 0x7
+ field public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32; // 0x20
field public static final int METADATA_KEY_VIDEO_HEIGHT = 19; // 0x13
field public static final int METADATA_KEY_VIDEO_ROTATION = 24; // 0x18
field public static final int METADATA_KEY_VIDEO_WIDTH = 18; // 0x12
diff --git a/api/system-current.txt b/api/system-current.txt
index c0c2311e5e3e..00e84626aa0c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24706,6 +24706,10 @@ package android.media {
field public static final java.lang.String KEY_DURATION = "durationUs";
field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
+ field public static final java.lang.String KEY_GRID_COLS = "grid-cols";
+ field public static final java.lang.String KEY_GRID_HEIGHT = "grid-height";
+ field public static final java.lang.String KEY_GRID_ROWS = "grid-rows";
+ field public static final java.lang.String KEY_GRID_WIDTH = "grid-width";
field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
field public static final java.lang.String KEY_HEIGHT = "height";
field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
@@ -24749,6 +24753,7 @@ package android.media {
field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+ field public static final java.lang.String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
@@ -24841,9 +24846,13 @@ package android.media {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
method public byte[] getEmbeddedPicture();
+ method public android.graphics.Bitmap getFrameAtIndex(int);
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
+ method public android.graphics.Bitmap[] getFramesAtIndex(int, int);
+ method public android.graphics.Bitmap getImageAtIndex(int);
+ method public android.graphics.Bitmap getPrimaryImage();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
@@ -24866,11 +24875,18 @@ package android.media {
field public static final int METADATA_KEY_DURATION = 9; // 0x9
field public static final int METADATA_KEY_GENRE = 6; // 0x6
field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
+ field public static final int METADATA_KEY_HAS_IMAGE = 26; // 0x1a
field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+ field public static final int METADATA_KEY_IMAGE_COUNT = 27; // 0x1b
+ field public static final int METADATA_KEY_IMAGE_HEIGHT = 30; // 0x1e
+ field public static final int METADATA_KEY_IMAGE_PRIMARY = 28; // 0x1c
+ field public static final int METADATA_KEY_IMAGE_ROTATION = 31; // 0x1f
+ field public static final int METADATA_KEY_IMAGE_WIDTH = 29; // 0x1d
field public static final int METADATA_KEY_LOCATION = 23; // 0x17
field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
field public static final int METADATA_KEY_TITLE = 7; // 0x7
+ field public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32; // 0x20
field public static final int METADATA_KEY_VIDEO_HEIGHT = 19; // 0x13
field public static final int METADATA_KEY_VIDEO_ROTATION = 24; // 0x18
field public static final int METADATA_KEY_VIDEO_WIDTH = 18; // 0x12
diff --git a/api/test-current.txt b/api/test-current.txt
index 909614460b87..c196a72724b9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -23016,6 +23016,10 @@ package android.media {
field public static final java.lang.String KEY_DURATION = "durationUs";
field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
+ field public static final java.lang.String KEY_GRID_COLS = "grid-cols";
+ field public static final java.lang.String KEY_GRID_HEIGHT = "grid-height";
+ field public static final java.lang.String KEY_GRID_ROWS = "grid-rows";
+ field public static final java.lang.String KEY_GRID_WIDTH = "grid-width";
field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
field public static final java.lang.String KEY_HEIGHT = "height";
field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
@@ -23059,6 +23063,7 @@ package android.media {
field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+ field public static final java.lang.String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
@@ -23151,9 +23156,13 @@ package android.media {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
method public byte[] getEmbeddedPicture();
+ method public android.graphics.Bitmap getFrameAtIndex(int);
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
+ method public android.graphics.Bitmap[] getFramesAtIndex(int, int);
+ method public android.graphics.Bitmap getImageAtIndex(int);
+ method public android.graphics.Bitmap getPrimaryImage();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
@@ -23176,11 +23185,18 @@ package android.media {
field public static final int METADATA_KEY_DURATION = 9; // 0x9
field public static final int METADATA_KEY_GENRE = 6; // 0x6
field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
+ field public static final int METADATA_KEY_HAS_IMAGE = 26; // 0x1a
field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+ field public static final int METADATA_KEY_IMAGE_COUNT = 27; // 0x1b
+ field public static final int METADATA_KEY_IMAGE_HEIGHT = 30; // 0x1e
+ field public static final int METADATA_KEY_IMAGE_PRIMARY = 28; // 0x1c
+ field public static final int METADATA_KEY_IMAGE_ROTATION = 31; // 0x1f
+ field public static final int METADATA_KEY_IMAGE_WIDTH = 29; // 0x1d
field public static final int METADATA_KEY_LOCATION = 23; // 0x17
field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
field public static final int METADATA_KEY_TITLE = 7; // 0x7
+ field public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32; // 0x20
field public static final int METADATA_KEY_VIDEO_HEIGHT = 19; // 0x13
field public static final int METADATA_KEY_VIDEO_ROTATION = 24; // 0x18
field public static final int METADATA_KEY_VIDEO_WIDTH = 18; // 0x12
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 56d4e4d940c2..cdaca1bf85d7 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -46,6 +46,7 @@ void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(msg);
+ flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
}
}
@@ -84,41 +85,40 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
it->second->finish();
mMetricsManagers.erase(it);
}
+ auto flushTime = mLastFlushTimes.find(key);
+ if (flushTime != mLastFlushTimes.end()) {
+ mLastFlushTimes.erase(flushTime);
+ }
}
-void StatsLogProcessor::addEventMetricData(const EventMetricData& eventMetricData) {
- // TODO: Replace this code when MetricsManager.onDumpReport() is ready to
- // get a list of byte arrays.
- flushIfNecessary(eventMetricData);
- const int numBytes = eventMetricData.ByteSize();
- char buffer[numBytes];
- eventMetricData.SerializeToArray(&buffer[0], numBytes);
- string bufferString(buffer, numBytes);
- mEvents.push_back(bufferString);
- mBufferSize += eventMetricData.ByteSize();
-}
+void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs,
+ const ConfigKey& key,
+ const unique_ptr<MetricsManager>& metricsManager) {
+ auto lastFlushNs = mLastFlushTimes.find(key);
+ if (lastFlushNs != mLastFlushTimes.end()) {
+ if (timestampNs - lastFlushNs->second < kMinFlushPeriod) {
+ return;
+ }
+ }
-void StatsLogProcessor::flushIfNecessary(const EventMetricData& eventMetricData) {
- if (eventMetricData.ByteSize() + mBufferSize > kMaxSerializedBytes) {
- flush();
+ size_t totalBytes = metricsManager->byteSize();
+ if (totalBytes > kMaxSerializedBytes) {
+ flush();
+ mLastFlushTimes[key] = std::move(timestampNs);
}
}
void StatsLogProcessor::flush() {
+ // TODO: Take ConfigKey as an argument and flush metrics related to the
+ // ConfigKey. Also, create a wrapper that holds a repeated field of
+ // StatsLogReport's.
+ /*
StatsLogReport logReport;
- for (string eventBuffer : mEvents) {
- EventMetricData eventFromBuffer;
- eventFromBuffer.ParseFromString(eventBuffer);
- EventMetricData* newEntry = logReport.mutable_event_metrics()->add_data();
- newEntry->CopyFrom(eventFromBuffer);
- }
-
const int numBytes = logReport.ByteSize();
vector<uint8_t> logReportBuffer(numBytes);
logReport.SerializeToArray(&logReportBuffer[0], numBytes);
mPushLog(logReportBuffer);
- mEvents.clear();
- mBufferSize = 0;
+ */
}
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 9cd74caf095e..6463441b7d75 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -50,6 +50,8 @@ public:
private:
std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
+ std::unordered_map<ConfigKey, long> mLastFlushTimes;
+
sp<UidMap> mUidMap; // Reference to the UidMap to lookup app name and version for each uid.
/* Max *serialized* size of the logs kept in memory before flushing through binder call.
@@ -59,25 +61,17 @@ private:
*/
static const size_t kMaxSerializedBytes = 16 * 1024;
- /* List of data that was captured for a single metric over a given interval of time. */
- vector<string> mEvents;
-
- /* Current *serialized* size of the logs kept in memory.
- To save computation, we will not calculate the size of the StatsLogReport every time when a
- new entry is added, which would recursively call ByteSize() on every log entry. Instead, we
- keep the sum of all individual stats log entry sizes. The size of a proto is approximately
- the sum of the size of all member protos.
- */
- size_t mBufferSize = 0;
-
/* Check if the buffer size exceeds the max buffer size when the new entry is added, and flush
the logs to callback clients if true. */
- void flushIfNecessary(const EventMetricData& eventMetricData);
-
- /* Append event metric data to StatsLogReport. */
- void addEventMetricData(const EventMetricData& eventMetricData);
+ void flushIfNecessary(uint64_t timestampNs,
+ const ConfigKey& key,
+ const unique_ptr<MetricsManager>& metricsManager);
std::function<void(const vector<uint8_t>&)> mPushLog;
+
+ /* Minimum period between two flushes in nanoseconds. Currently set to 10
+ * minutes. */
+ static const unsigned long long kMinFlushPeriod = 600 * NS_PER_SEC;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 7bb9c8a502c1..69f336f420fc 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -203,6 +203,13 @@ void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) {
(long long)mCurrentBucketStartTimeNs);
}
+size_t CountMetricProducer::byteSize() {
+// TODO: return actual proto size when ProtoOutputStream is ready for use for
+// CountMetricsProducer.
+// return mProto->size();
+ return 0;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 340c8309b7fa..be77e4739e8e 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -49,6 +49,8 @@ public:
void onSlicedConditionMayChange() override;
+ size_t byteSize() override;
+
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 38e55fde40d5..a590bc856966 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -349,6 +349,13 @@ void DurationMetricProducer::flushDurationIfNeeded(const uint64_t eventTime) {
}
}
+size_t DurationMetricProducer::byteSize() {
+// TODO: return actual proto size when ProtoOutputStream is ready for use for
+// DurationMetricsProducer.
+// return mProto->size();
+ return 0;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 19e2437ca538..8820403a32fb 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -69,6 +69,8 @@ public:
void onSlicedConditionMayChange() override;
+ size_t byteSize() override;
+
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 8b3f405eec80..7e0610514679 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -127,6 +127,10 @@ void EventMetricProducer::onMatchedLogEventInternal(
mProto->end(wrapperToken);
}
+size_t EventMetricProducer::byteSize() {
+ return mProto->size();
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 879175cc25ff..14fa31cce145 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -51,6 +51,8 @@ public:
void onSlicedConditionMayChange() override;
+ size_t byteSize() override;
+
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 496b1453e46c..80eb527f3bdf 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -64,6 +64,8 @@ public:
return mConditionSliced;
};
+ virtual size_t byteSize() = 0;
+
protected:
const uint64_t mStartTimeNs;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 1ffa58b8c862..4fa3965a9dd2 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -150,6 +150,15 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
}
}
+// Returns the total byte size of all metrics managed by a single config source.
+size_t MetricsManager::byteSize() {
+ size_t totalSize = 0;
+ for (auto metricProducer : mAllMetricProducers) {
+ totalSize += metricProducer->byteSize();
+ }
+ return totalSize;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 2f91460061fa..44cd6371199e 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -46,6 +46,8 @@ public:
// Config source owner can call onDumpReport() to get all the metrics collected.
std::vector<StatsLogReport> onDumpReport();
+ size_t byteSize();
+
private:
// All event tags that are interesting to my metrics.
std::set<int> mTagIds;
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 29cd94b21b1b..ec91509aaf40 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -69,6 +69,34 @@ message DurationMetricData {
repeated DurationBucketInfo bucket_info = 2;
}
+message ValueBucketInfo {
+ optional int64 start_bucket_nanos = 1;
+
+ optional int64 end_bucket_nanos = 2;
+
+ optional int64 value = 3;
+}
+
+message ValueMetricData {
+ repeated KeyValuePair dimension = 1;
+
+ repeated ValueBucketInfo bucket_info = 2;
+}
+
+message GaugeBucketInfo {
+ optional int64 start_bucket_nanos = 1;
+
+ optional int64 end_bucket_nanos = 2;
+
+ optional int64 gauge = 3;
+}
+
+message GaugeMetricData {
+ repeated KeyValuePair dimension = 1;
+
+ repeated GaugeBucketInfo bucket_info = 2;
+}
+
message UidMapping {
message AppInfo {
optional string app = 1;
@@ -83,7 +111,7 @@ message UidMapping {
message Change {
optional bool deletion = 1;
- optional int64 timestamp = 2;
+ optional int64 timestamp_nanos = 2;
optional string app = 3;
optional int32 uid = 4;
@@ -108,9 +136,29 @@ message StatsLogReport {
message DurationMetricDataWrapper {
repeated DurationMetricData data = 1;
}
+ message ValueMetricDataWrapper {
+ repeated ValueMetricData data = 1;
+ }
+ message GaugeMetricDataWrapper {
+ repeated GaugeMetricData data = 1;
+ }
oneof data {
EventMetricDataWrapper event_metrics = 4;
CountMetricDataWrapper count_metrics = 5;
DurationMetricDataWrapper duration_metrics = 6;
+ ValueMetricDataWrapper value_metrics = 7;
+ GaugeMetricDataWrapper gauge_metrics = 8;
+ }
+}
+
+message ConfigMetricsReport {
+ message ConfigKey {
+ optional int32 uid = 1;
+ optional string name = 2;
}
+ optional ConfigKey config_key = 1;
+
+ repeated StatsLogReport metrics = 2;
+
+ optional UidMapping uid_map = 3;
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 113ac62699d2..a4d2421b16d3 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -168,7 +168,28 @@ message DurationMetric {
optional Bucket bucket = 8;
- repeated EventConditionLink links = 9;
+ repeated Alert alerts = 9;
+
+ repeated EventConditionLink links = 10;
+
+}
+
+message GaugeMetric {
+ optional int64 metric_id = 1;
+
+ optional string what = 2;
+
+ optional int32 gauge_field = 3;
+
+ optional string condition = 4;
+
+ repeated KeyMatcher dimension = 5;
+
+ optional Bucket bucket = 6;
+
+ repeated Alert alerts = 7;
+
+ repeated EventConditionLink links = 8;
}
message ValueMetric {
@@ -184,6 +205,10 @@ message ValueMetric {
optional Bucket bucket = 6;
+ repeated Alert alerts = 7;
+
+ repeated EventConditionLink links = 8;
+
enum Operation {
SUM_DIFF = 1;
MIN_DIFF = 2;
@@ -194,14 +219,14 @@ message ValueMetric {
FIRST = 7;
LAST = 8;
}
- optional Operation operation = 7;
+ optional Operation operation = 9 [default = SUM];
}
message EventConditionLink {
- optional string condition = 1;
+ optional string condition = 1;
- repeated KeyMatcher key_in_main = 2;
- repeated KeyMatcher key_in_condition = 3;
+ repeated KeyMatcher key_in_main = 2;
+ repeated KeyMatcher key_in_condition = 3;
};
message StatsdConfig {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8d9dc1fab4ff..23059576fdc4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -682,20 +682,21 @@ public class ActivityManager {
}
/**
- * Input parameter to {@link android.app.IActivityManager#moveTaskToDockedStack} which
- * specifies the position of the created docked stack at the top half of the screen if
+ * Parameter to {@link android.app.IActivityManager#setTaskWindowingModeSplitScreenPrimary}
+ * which specifies the position of the created docked stack at the top half of the screen if
* in portrait mode or at the left half of the screen if in landscape mode.
* @hide
*/
- public static final int DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT = 0;
+ public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
/**
- * Input parameter to {@link android.app.IActivityManager#moveTaskToDockedStack} which
+ * Parameter to {@link android.app.IActivityManager#setTaskWindowingModeSplitScreenPrimary}
+ * which
* specifies the position of the created docked stack at the bottom half of the screen if
* in portrait mode or at the right half of the screen if in landscape mode.
* @hide
*/
- public static final int DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
+ public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
/**
* Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index b62e4c2d0028..4a21f5c424d5 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,7 +16,7 @@
package android.app;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
@@ -203,10 +203,11 @@ public class ActivityOptions {
"android.activity.taskOverlayCanResume";
/**
- * Where the docked stack should be positioned.
+ * Where the split-screen-primary stack should be positioned.
* @hide
*/
- private static final String KEY_DOCK_CREATE_MODE = "android:activity.dockCreateMode";
+ private static final String KEY_SPLIT_SCREEN_CREATE_MODE =
+ "android:activity.splitScreenCreateMode";
/**
* Determines whether to disallow the outgoing activity from entering picture-in-picture as the
@@ -292,7 +293,7 @@ public class ActivityOptions {
@WindowConfiguration.ActivityType
private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
private int mLaunchTaskId = -1;
- private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
private boolean mTaskOverlay;
private boolean mTaskOverlayCanResume;
@@ -884,7 +885,8 @@ public class ActivityOptions {
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
- mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
+ mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, false);
if (opts.containsKey(KEY_ANIM_SPECS)) {
@@ -1194,13 +1196,13 @@ public class ActivityOptions {
}
/** @hide */
- public int getDockCreateMode() {
- return mDockCreateMode;
+ public int getSplitScreenCreateMode() {
+ return mSplitScreenCreateMode;
}
/** @hide */
- public void setDockCreateMode(int dockCreateMode) {
- mDockCreateMode = dockCreateMode;
+ public void setSplitScreenCreateMode(int splitScreenCreateMode) {
+ mSplitScreenCreateMode = splitScreenCreateMode;
}
/** @hide */
@@ -1369,7 +1371,7 @@ public class ActivityOptions {
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
- b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
+ b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
mDisallowEnterPictureInPictureWhileLaunching);
if (mAnimSpecs != null) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4bd85ae9ee5c..b6fb12018201 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -254,8 +254,10 @@ public class AppOpsManager {
public static final int OP_ANSWER_PHONE_CALLS = 69;
/** @hide Run jobs when in background */
public static final int OP_RUN_ANY_IN_BACKGROUND = 70;
+ /** @hide Change Wi-Fi connectivity state */
+ public static final int OP_CHANGE_WIFI_STATE = 71;
/** @hide */
- public static final int _NUM_OP = 71;
+ public static final int _NUM_OP = 72;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -496,6 +498,7 @@ public class AppOpsManager {
OP_INSTANT_APP_START_FOREGROUND,
OP_ANSWER_PHONE_CALLS,
OP_RUN_ANY_IN_BACKGROUND,
+ OP_CHANGE_WIFI_STATE,
};
/**
@@ -574,6 +577,7 @@ public class AppOpsManager {
OPSTR_INSTANT_APP_START_FOREGROUND,
OPSTR_ANSWER_PHONE_CALLS,
null, // OP_RUN_ANY_IN_BACKGROUND
+ null, // OP_CHANGE_WIFI_STATE
};
/**
@@ -652,6 +656,7 @@ public class AppOpsManager {
"INSTANT_APP_START_FOREGROUND",
"ANSWER_PHONE_CALLS",
"RUN_ANY_IN_BACKGROUND",
+ "CHANGE_WIFI_STATE",
};
/**
@@ -730,6 +735,7 @@ public class AppOpsManager {
Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
Manifest.permission.ANSWER_PHONE_CALLS,
null, // no permission for OP_RUN_ANY_IN_BACKGROUND
+ Manifest.permission.CHANGE_WIFI_STATE,
};
/**
@@ -809,6 +815,7 @@ public class AppOpsManager {
null, // INSTANT_APP_START_FOREGROUND
null, // ANSWER_PHONE_CALLS
null, // OP_RUN_ANY_IN_BACKGROUND
+ null, // OP_CHANGE_WIFI_STATE
};
/**
@@ -887,6 +894,7 @@ public class AppOpsManager {
false, // INSTANT_APP_START_FOREGROUND
false, // ANSWER_PHONE_CALLS
false, // OP_RUN_ANY_IN_BACKGROUND
+ false, // OP_CHANGE_WIFI_STATE
};
/**
@@ -964,6 +972,7 @@ public class AppOpsManager {
AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
AppOpsManager.MODE_ALLOWED, // OP_RUN_ANY_IN_BACKGROUND
+ AppOpsManager.MODE_ALLOWED, // OP_CHANGE_WIFI_STATE
};
/**
@@ -1045,6 +1054,7 @@ public class AppOpsManager {
false,
false, // ANSWER_PHONE_CALLS
false, // OP_RUN_ANY_IN_BACKGROUND
+ false, // OP_CHANGE_WIFI_STATE
};
/**
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 18f052589d94..e8cce0f3a0de 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -502,8 +502,8 @@ interface IActivityManager {
void exitFreeformMode(in IBinder token);
void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
- boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
- in Rect initialBounds);
+ boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+ boolean animate, in Rect initialBounds);
/**
* Dismisses split-screen multi-window mode.
* {@param toTop} If true the current primary split-screen stack will be placed or left on top.
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index 0f1e2597f39e..d1ce60e9ff08 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -1,6 +1,6 @@
ek@google.com
hugobenichi@google.com
-jsharkey@google.com
+jsharkey@android.com
lorenzo@google.com
satk@google.com
silberst@google.com
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ee3e5bc9a001..6ce12c161714 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -2339,7 +2339,8 @@ public final class StrictMode {
/** Stack and violation details. */
@Nullable private final Throwable mThrowable;
- private final Deque<Throwable> mBinderStack = new ArrayDeque<>();
+ /** Path leading to a violation that occurred across binder. */
+ private final Deque<StackTraceElement[]> mBinderStack = new ArrayDeque<>();
/** Memoized stack trace of full violation. */
@Nullable private String mStackTrace;
@@ -2421,9 +2422,13 @@ public final class StrictMode {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 256);
mThrowable.printStackTrace(pw);
- for (Throwable t : mBinderStack) {
+ for (StackTraceElement[] traces : mBinderStack) {
pw.append("# via Binder call with stack:\n");
- t.printStackTrace(pw);
+ for (StackTraceElement traceElement : traces) {
+ pw.append("\tat ");
+ pw.append(traceElement.toString());
+ pw.append('\n');
+ }
}
pw.flush();
pw.close();
@@ -2456,12 +2461,13 @@ public final class StrictMode {
}
/**
- * Add a {@link Throwable} from the current process that caused the underlying violation.
+ * Add a {@link Throwable} from the current process that caused the underlying violation. We
+ * only preserve the stack trace elements.
*
* @hide
*/
void addLocalStack(Throwable t) {
- mBinderStack.addFirst(t);
+ mBinderStack.addFirst(t.getStackTrace());
}
/**
@@ -2530,7 +2536,17 @@ public final class StrictMode {
mThrowable = (Throwable) in.readSerializable();
int binderStackSize = in.readInt();
for (int i = 0; i < binderStackSize; i++) {
- mBinderStack.add((Throwable) in.readSerializable());
+ StackTraceElement[] traceElements = new StackTraceElement[in.readInt()];
+ for (int j = 0; j < traceElements.length; j++) {
+ StackTraceElement element =
+ new StackTraceElement(
+ in.readString(),
+ in.readString(),
+ in.readString(),
+ in.readInt());
+ traceElements[j] = element;
+ }
+ mBinderStack.add(traceElements);
}
int rawPolicy = in.readInt();
if (unsetGatheringBit) {
@@ -2552,8 +2568,14 @@ public final class StrictMode {
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(mThrowable);
dest.writeInt(mBinderStack.size());
- for (Throwable t : mBinderStack) {
- dest.writeSerializable(t);
+ for (StackTraceElement[] traceElements : mBinderStack) {
+ dest.writeInt(traceElements.length);
+ for (StackTraceElement element : traceElements) {
+ dest.writeString(element.getClassName());
+ dest.writeString(element.getMethodName());
+ dest.writeString(element.getFileName());
+ dest.writeInt(element.getLineNumber());
+ }
}
int start = dest.dataPosition();
dest.writeInt(policy);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 3d38dc41aa9a..65bde49520d3 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -385,7 +385,7 @@ interface IWindowManager
/**
* Create an input consumer by name.
*/
- void createInputConsumer(String name, out InputChannel inputChannel);
+ void createInputConsumer(IBinder token, String name, out InputChannel inputChannel);
/**
* Destroy an input consumer by name. This method will also dispose the input channels
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index b2053c004e2f..b8bfc6491f70 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -25,6 +25,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
+import android.os.SystemProperties;
import android.provider.Settings.Secure;
import android.provider.Settings.System;
import android.util.Slog;
@@ -100,6 +101,12 @@ public final class NightDisplayController {
*/
public static final int COLOR_MODE_SATURATED = 2;
+ /**
+ * See com.android.server.display.DisplayTransformManager.
+ */
+ private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
+ private static final String PERSISTENT_PROPERTY_NATIVE_MODE = "persist.sys.sf.native_mode";
+
private final Context mContext;
private final int mUserId;
@@ -334,9 +341,15 @@ public final class NightDisplayController {
*/
public int getColorMode() {
final int colorMode = System.getIntForUser(mContext.getContentResolver(),
- System.DISPLAY_COLOR_MODE, COLOR_MODE_BOOSTED, mUserId);
+ System.DISPLAY_COLOR_MODE, -1, mUserId);
if (colorMode < COLOR_MODE_NATURAL || colorMode > COLOR_MODE_SATURATED) {
- return COLOR_MODE_BOOSTED;
+ // There still might be a legacy system property controlling color mode that we need to
+ // respect.
+ if ("1".equals(SystemProperties.get(PERSISTENT_PROPERTY_NATIVE_MODE))) {
+ return COLOR_MODE_SATURATED;
+ }
+ return "1.0".equals(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
+ ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
}
return colorMode;
}
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index 7cb32ff793e7..e2064a8099ae 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -2,5 +2,5 @@ set noparent
ek@google.com
hugobenichi@google.com
-jsharkey@google.com
+jsharkey@android.com
lorenzo@google.com
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 8d9630fe5654..e5ad1f47d37d 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -804,7 +804,7 @@ public class StateMachine {
/** State that processed the message */
State msgProcessedState = null;
- if (mIsConstructionCompleted) {
+ if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 57dd73f5a192..aa83d1d52b55 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1653,7 +1653,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Da otkačite ovaj ekran, dodirnite i držite dugmad Nazad i Pregled."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Ova aplikacija se ne može otkačiti"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran je otkačen"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN prije nego se otkači"</string>
@@ -1819,14 +1818,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test poruka za hitne slučajeve"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovori"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM kartica nije dozvoljena za govor"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM kartica nije dodijeljena za govor"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM kartica nije dozvoljena za govor"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon nije dozvoljen za govor"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Iskočni prozor"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Za ovu prečicu potrebna je najnovija aplikacija"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index cb7500429edd..57312e7444e0 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1635,8 +1635,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dihapus oleh admin Anda"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan sebagian besar data latar belakang. Email, pesan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
- <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah disentuh."</string>
- <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Data?"</string>
+ <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan data, Penghemat Kuota Internet mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah disentuh."</string>
+ <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Kuota Internet?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktifkan"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Selama %1$d menit (hingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index aa2cc3d1ed44..1976bbe6bfe0 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1231,7 +1231,7 @@
<string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"아직 <xliff:g id="NAME">%s</xliff:g> 꺼내는 중…"</string>
<string name="ext_media_unmounting_notification_message" msgid="4182843895023357756">"삭제하지 마세요."</string>
<string name="ext_media_init_action" msgid="7952885510091978278">"설정"</string>
- <string name="ext_media_unmount_action" msgid="1121883233103278199">"꺼내기"</string>
+ <string name="ext_media_unmount_action" msgid="1121883233103278199">"마운트 해제"</string>
<string name="ext_media_browse_action" msgid="8322172381028546087">"둘러보기"</string>
<string name="ext_media_missing_title" msgid="620980315821543904">"<xliff:g id="NAME">%s</xliff:g> 없음"</string>
<string name="ext_media_missing_message" msgid="5761133583368750174">"기기 다시 삽입"</string>
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"두 번째 업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"세 번째 업무용<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"이 화면을 고정 해제하려면 \'뒤로\' 및 \'최근 사용\'을 길게 터치하세요."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"이 앱은 고정 해제할 수 없습니다."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"화면 고정 해제됨"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"긴급 메시지 테스트"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"답장"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM에서 음성이 허용되지 않음"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM이 음성으로 프로비저닝되지 않음"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM에서 음성이 허용되지 않음"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"휴대전화에서 음성이 허용되지 않음"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"팝업 창"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g>개 더보기"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"바로가기를 사용하려면 최신 앱이 필요합니다"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index cc6cdc93b76c..d7c10ecb76cb 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1676,7 +1676,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> – praca 2"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> – praca 3"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Aby odpiąć ten ekran, naciśnij i przytrzymaj Wstecz oraz Przegląd"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Tej aplikacji nie można odpiąć"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran przypięty"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran odpięty"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Podaj PIN, aby odpiąć"</string>
@@ -1852,14 +1851,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test komunikatów alarmowych"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odpowiedz"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Karta SIM jest niedozwolona w przypadku usług głosowych"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Karta SIM nie jest obsługiwana w przypadku usług głosowych"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Karta SIM jest niedozwolona w przypadku usług głosowych"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon jest niedozwolony w przypadku usług głosowych"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Wyskakujące okienko"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ten skrót wymaga zainstalowania najnowszej wersji aplikacji"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index af5cfeca6004..2de83c6106d5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -610,7 +610,7 @@
<item msgid="3145118944639869809">"Personalizado"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Emprego"</item>
+ <item msgid="7546335612189115615">"Trabalho"</item>
<item msgid="4378074129049520373">"Outro"</item>
<item msgid="3455047468583965104">"Personalizado"</item>
</string-array>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 62b54d2b5c61..429ecf109bfd 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2வது பணி <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3வது பணி <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"இந்தத் திரையை அகற்ற, முந்தையது, மேலோட்டப் பார்வை ஆகிய இரண்டு பொத்தானையும் தொட்டுப் பிடித்திருக்கவும்"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"இந்தப் பயன்பாட்டை அகற்ற முடியாது"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"திரை பின் செய்யப்பட்டது"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"திரையின் பின் அகற்றப்பட்டது"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"அவசரக் காலச் செய்திகளுக்கான சோதனை"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"பதிலளிக்கும்"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"குரல் அழைப்பை மேற்கொள்ள இந்த சிம்மிற்கு அனுமதி இல்லை"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"குரல் அழைப்பை மேற்கொள்ளும் வசதி இந்த சிம்மிற்கு இல்லை"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"குரல் அழைப்பை மேற்கொள்ள இந்த சிம்மிற்கு அனுமதி இல்லை"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"குரல் அழைப்பை மேற்கொள்ள இந்த ஃபோனுக்கு அனுமதி இல்லை"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"பாப்அப் சாளரம்"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"இந்த ஷார்ட்கட்டைப் பயன்படுத்த, சமீபத்திய பயன்பாடு வேண்டும்"</string>
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 3e0348123618..bbdbdb13b3f7 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -26,12 +26,10 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
-import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
import static android.widget.espresso.DragHandleUtils.onHandleView;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
-import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
@@ -61,6 +59,7 @@ import android.support.test.espresso.action.EspressoKey;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.Suppress;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
@@ -216,7 +215,6 @@ public class TextViewActivityTest {
onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
onView(withId(R.id.textview)).check(hasSelection(""));
- assertNoSelectionHandles();
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
// Test undo returns to the original state.
@@ -269,18 +267,12 @@ public class TextViewActivityTest {
@Test
public void testToolbarAppearsAfterSelection() {
final String text = "Toolbar appears after selection.";
- assertFloatingToolbarIsNotDisplayed();
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(
longPressOnTextAtIndex(text.indexOf("appears")));
sleepForFloatingToolbarPopup();
assertFloatingToolbarIsDisplayed();
-
- final String text2 = "Toolbar disappears after typing text.";
- onView(withId(R.id.textview)).perform(replaceText(text2));
- sleepForFloatingToolbarPopup();
- assertFloatingToolbarIsNotDisplayed();
}
@Test
@@ -310,7 +302,6 @@ public class TextViewActivityTest {
@Test
public void testToolbarAndInsertionHandle() {
final String text = "text";
- assertFloatingToolbarIsNotDisplayed();
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
@@ -404,8 +395,6 @@ public class TextViewActivityTest {
final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(replaceText(text));
- assertNoSelectionHandles();
-
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -428,8 +417,6 @@ public class TextViewActivityTest {
final String text = "abc \u0621\u0622\u0623 def";
onView(withId(R.id.textview)).perform(replaceText(text));
- assertNoSelectionHandles();
-
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622')));
onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -491,6 +478,7 @@ public class TextViewActivityTest {
onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr"));
}
+ @Suppress // Consistently failing.
@Test
public void testSelectionHandles_multiLine_rtl() {
// Arabic text.
@@ -649,13 +637,11 @@ public class TextViewActivityTest {
onView(withId(R.id.textview)).perform(replaceText(text));
final TextView textView = mActivity.findViewById(R.id.textview);
- assertFloatingToolbarIsNotDisplayed();
mActivityRule.runOnUiThread(
() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
mInstrumentation.waitForIdleSync();
- sleepForFloatingToolbarPopup();
// Don't automatically start action mode.
- assertFloatingToolbarIsNotDisplayed();
+ // TODO: Implement assertActionModeNotStarted()
// Make sure that "Select All" is included in the selection action mode when the entire text
// is not selected.
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
@@ -685,8 +671,6 @@ public class TextViewActivityTest {
() -> Selection.setSelection((Spannable) textView.getText(), 0));
mInstrumentation.waitForIdleSync();
- sleepForFloatingToolbarPopup();
- assertFloatingToolbarIsNotDisplayed();
// Make sure that user click can trigger the insertion action mode.
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
diff --git a/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java b/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
index 6a2233ba126e..1693e548f7bd 100644
--- a/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
@@ -36,6 +36,10 @@ public final class DragHandleUtils {
private DragHandleUtils() {}
+ /**
+ * @deprecated Negative assertions are taking too long to timeout in Espresso.
+ */
+ @Deprecated
public static void assertNoSelectionHandles() {
try {
onView(isAssignableFrom(Editor.SelectionHandleView.class))
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index f7069b31710f..b6986d5c5a68 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -87,7 +87,9 @@ public class FloatingToolbarEspressoUtils {
* Asserts that the floating toolbar is not displayed on screen.
*
* @throws AssertionError if the assertion fails
+ * @deprecated Negative assertions are taking too long to timeout in Espresso.
*/
+ @Deprecated
public static void assertFloatingToolbarIsNotDisplayed() {
try {
onFloatingToolBar().check(matches(isDisplayed()));
@@ -173,12 +175,31 @@ public class FloatingToolbarEspressoUtils {
* @throws AssertionError if the assertion fails
*/
public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
- try{
- assertFloatingToolbarContainsItem(itemLabel);
- } catch (AssertionError e) {
- return;
- }
- throw new AssertionError("Floating toolbar contains " + itemLabel);
+ onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
+ @Override
+ public boolean matchesSafely(View view) {
+ return doesNotContainItem(view);
+ }
+
+ @Override
+ public void describeTo(Description description) {}
+
+ private boolean doesNotContainItem(View view) {
+ if (view.getTag() instanceof MenuItem) {
+ if (itemLabel.equals(((MenuItem) view.getTag()).getTitle().toString())) {
+ return false;
+ }
+ } else if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ if (doesNotContainItem(viewGroup.getChildAt(i))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }));
}
/**
diff --git a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index eb2a5165dc4f..76aa93f7e8be 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -24,6 +24,7 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
+import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.Suppress;
import com.android.internal.util.State;
@@ -343,6 +344,100 @@ public class StateMachineTest extends TestCase {
}
/**
+ * Tests {@link StateMachine#quitNow()} immediately after {@link StateMachine#start()}.
+ */
+ class StateMachineQuitNowAfterStartTest extends StateMachine {
+ Collection<LogRec> mLogRecs;
+
+ StateMachineQuitNowAfterStartTest(String name, Looper looper) {
+ super(name, looper);
+ mThisSm = this;
+ setDbg(DBG);
+
+ // Setup state machine with 1 state
+ addState(mS1);
+
+ // Set the initial state
+ setInitialState(mS1);
+ }
+
+ @Override
+ public void onQuitting() {
+ tlog("onQuitting");
+ addLogRec(ON_QUITTING);
+ mLogRecs = mThisSm.copyLogRecs();
+ synchronized (mThisSm) {
+ mThisSm.notifyAll();
+ }
+ }
+
+ class S1 extends State {
+ @Override
+ public void enter() {
+ tlog("S1.enter");
+ addLogRec(ENTER);
+ }
+ @Override
+ public void exit() {
+ tlog("S1.exit");
+ addLogRec(EXIT);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ switch(message.what) {
+ // Sleep and assume the other messages will be queued up.
+ case TEST_CMD_1: {
+ tlog("TEST_CMD_1");
+ sleep(500);
+ break;
+ }
+ default: {
+ tlog("default what=" + message.what);
+ break;
+ }
+ }
+ return HANDLED;
+ }
+ }
+
+ private StateMachineQuitNowAfterStartTest mThisSm;
+ private S1 mS1 = new S1();
+ }
+
+ /**
+ * When quitNow() is called immediately after start(), the QUIT_CMD gets processed
+ * before the INIT_CMD. This test ensures that the StateMachine can gracefully handle
+ * this sequencing of messages (QUIT before INIT).
+ */
+ @SmallTest
+ public void testStateMachineQuitNowAfterStart() throws Exception {
+ if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
+
+ TestLooper testLooper = new TestLooper();
+ StateMachineQuitNowAfterStartTest smQuitNowAfterStartTest =
+ new StateMachineQuitNowAfterStartTest(
+ "smQuitNowAfterStartTest", testLooper.getLooper());
+ smQuitNowAfterStartTest.start();
+ smQuitNowAfterStartTest.quitNow();
+ if (smQuitNowAfterStartTest.isDbg()) tlog("testStateMachineQuitNowAfterStart E");
+
+ testLooper.dispatchAll();
+ dumpLogRecs(smQuitNowAfterStartTest.mLogRecs);
+ assertEquals(2, smQuitNowAfterStartTest.mLogRecs.size());
+
+ LogRec lr;
+ Iterator<LogRec> itr = smQuitNowAfterStartTest.mLogRecs.iterator();
+ lr = itr.next();
+ assertEquals(EXIT, lr.getInfo());
+ assertEquals(smQuitNowAfterStartTest.mS1, lr.getState());
+
+ lr = itr.next();
+ assertEquals(ON_QUITTING, lr.getInfo());
+
+ if (smQuitNowAfterStartTest.isDbg()) tlog("testStateMachineQuitNowAfterStart X");
+ }
+
+ /**
* Test enter/exit can use transitionTo
*/
class StateMachineEnterExitTransitionToTest extends StateMachine {
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 90d6ab867fe1..e74dc6dc9671 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -132,7 +132,7 @@ import dalvik.annotation.optimization.FastNative;
* <td>translateY</td>
* </tr>
* <tr>
- * <td rowspan="8">&lt;path&gt;</td>
+ * <td rowspan="9">&lt;path&gt;</td>
* <td>pathData</td>
* </tr>
* <tr>
@@ -154,6 +154,9 @@ import dalvik.annotation.optimization.FastNative;
* <td>trimPathStart</td>
* </tr>
* <tr>
+ * <td>trimPathEnd</td>
+ * </tr>
+ * <tr>
* <td>trimPathOffset</td>
* </tr>
* <tr>
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index ceac3253e178..7b2e21a40f8b 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -213,12 +213,79 @@ import dalvik.system.VMRuntime;
* &lt;/vector&gt;
* </pre>
* </li>
- * <li>And here is an example of linear gradient color, which is supported in SDK 24+.
+ * <h4>Gradient support</h4>
+ * We support 3 types of gradients: {@link android.graphics.LinearGradient},
+ * {@link android.graphics.RadialGradient}, or {@link android.graphics.SweepGradient}.
+ * <p/>
+ * And we support all of 3 types of tile modes {@link android.graphics.Shader.TileMode}:
+ * CLAMP, REPEAT, MIRROR.
+ * <p/>
+ * All of the attributes are listed in {@link android.R.styleable#GradientColor}.
+ * Note that different attributes are relevant for different types of gradient.
+ * <table border="2" align="center" cellpadding="5">
+ * <thead>
+ * <tr>
+ * <th>LinearGradient</th>
+ * <th>RadialGradient</th>
+ * <th>SweepGradient</th>
+ * </tr>
+ * </thead>
+ * <tr>
+ * <td>startColor </td>
+ * <td>startColor</td>
+ * <td>startColor</td>
+ * </tr>
+ * <tr>
+ * <td>centerColor</td>
+ * <td>centerColor</td>
+ * <td>centerColor</td>
+ * </tr>
+ * <tr>
+ * <td>endColor</td>
+ * <td>endColor</td>
+ * <td>endColor</td>
+ * </tr>
+ * <tr>
+ * <td>type</td>
+ * <td>type</td>
+ * <td>type</td>
+ * </tr>
+ * <tr>
+ * <td>tileMode</td>
+ * <td>tileMode</td>
+ * <td>tileMode</td>
+ * </tr>
+ * <tr>
+ * <td>startX</td>
+ * <td>centerX</td>
+ * <td>centerX</td>
+ * </tr>
+ * <tr>
+ * <td>startY</td>
+ * <td>centerY</td>
+ * <td>centerY</td>
+ * </tr>
+ * <tr>
+ * <td>endX</td>
+ * <td>gradientRadius</td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td>endY</td>
+ * <td></td>
+ * <td></td>
+ * </tr>
+ * </table>
+ * <p/>
+ * Also note that if any color item {@link android.R.styleable#GradientColorItem} is defined, then
+ * startColor, centerColor and endColor will be ignored.
+ * <p/>
* See more details in {@link android.R.styleable#GradientColor} and
* {@link android.R.styleable#GradientColorItem}.
+ * <p/>
+ * Here is a simple example that defines a linear gradient.
* <pre>
* &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"
- * android:angle="90"
* android:startColor="?android:attr/colorPrimary"
* android:endColor="?android:attr/colorControlActivated"
* android:centerColor="#f00"
@@ -229,7 +296,18 @@ import dalvik.system.VMRuntime;
* android:type="linear"&gt;
* &lt;/gradient&gt;
* </pre>
- * </li>
+ * And here is a simple example that defines a radial gradient using color items.
+ * <pre>
+ * &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:centerX="300"
+ * android:centerY="300"
+ * android:gradientRadius="100"
+ * android:type="radial"&gt;
+ * &lt;item android:offset="0.1" android:color="#0ff"/&gt;
+ * &lt;item android:offset="0.4" android:color="#fff"/&gt;
+ * &lt;item android:offset="0.9" android:color="#ff0"/&gt;
+ * &lt;/gradient&gt;
+ * </pre>
*
*/
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 87999c353a90..17de8fa1e7a5 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2847,14 +2847,111 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool can
}
memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
}
-}
-/* static */ inline bool assignLocaleComponent(ResTable_config* config,
- const char* start, size_t size) {
+ /* TODO: Add BCP47 extension. It requires RESTABLE_MAX_LOCALE_LEN
+ * increase from 28 to 42 bytes (-u-nu-xxxxxxxx) */
+}
+
+struct LocaleParserState {
+ enum State : uint8_t {
+ BASE, UNICODE_EXTENSION, IGNORE_THE_REST
+ } parserState;
+ enum UnicodeState : uint8_t {
+ /* Initial state after the Unicode singleton is detected. Either a keyword
+ * or an attribute is expected. */
+ NO_KEY,
+ /* Unicode extension key (but not attribute) is expected. Next states:
+ * NO_KEY, IGNORE_KEY or NUMBERING_SYSTEM. */
+ EXPECT_KEY,
+ /* A key is detected, however it is not supported for now. Ignore its
+ * value. Next states: IGNORE_KEY or NUMBERING_SYSTEM. */
+ IGNORE_KEY,
+ /* Numbering system key was detected. Store its value in the configuration
+ * localeNumberingSystem field. Next state: EXPECT_KEY */
+ NUMBERING_SYSTEM
+ } unicodeState;
+
+ LocaleParserState(): parserState(BASE), unicodeState(NO_KEY) {}
+};
+
+/* static */ inline LocaleParserState assignLocaleComponent(ResTable_config* config,
+ const char* start, size_t size, LocaleParserState state) {
+
+ /* It is assumed that this function is not invoked with state.parserState
+ * set to IGNORE_THE_REST. The condition is checked by setBcp47Locale
+ * function. */
+
+ if (state.parserState == LocaleParserState::UNICODE_EXTENSION) {
+ switch (size) {
+ case 1:
+ /* Other BCP 47 extensions are not supported at the moment */
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
+ break;
+ case 2:
+ if (state.unicodeState == LocaleParserState::NO_KEY ||
+ state.unicodeState == LocaleParserState::EXPECT_KEY) {
+ /* Analyze Unicode extension key. Currently only 'nu'
+ * (numbering system) is supported.*/
+ if ((start[0] == 'n' || start[0] == 'N') &&
+ (start[1] == 'u' || start[1] == 'U')) {
+ state.unicodeState = LocaleParserState::NUMBERING_SYSTEM;
+ } else {
+ state.unicodeState = LocaleParserState::IGNORE_KEY;
+ }
+ } else {
+ /* Keys are not allowed in other state allowed, ignore the rest. */
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
+ }
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ switch (state.unicodeState) {
+ case LocaleParserState::NUMBERING_SYSTEM:
+ /* Accept only the first occurrence of the numbering system. */
+ if (config->localeNumberingSystem[0] == '\0') {
+ for (size_t i = 0; i < size; ++i) {
+ config->localeNumberingSystem[i] = tolower(start[i]);
+ }
+ state.unicodeState = LocaleParserState::EXPECT_KEY;
+ } else {
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
+ }
+ break;
+ case LocaleParserState::IGNORE_KEY:
+ /* Unsupported Unicode keyword. Ignore. */
+ state.unicodeState = LocaleParserState::EXPECT_KEY;
+ break;
+ case LocaleParserState::EXPECT_KEY:
+ /* A keyword followed by an attribute is not allowed. */
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
+ break;
+ case LocaleParserState::NO_KEY:
+ /* Extension attribute. Do nothing. */
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ /* Unexpected field length - ignore the rest and treat as an error */
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
+ }
+ return state;
+ }
switch (size) {
case 0:
- return false;
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
+ break;
+ case 1:
+ state.parserState = (start[0] == 'u' || start[0] == 'U')
+ ? LocaleParserState::UNICODE_EXTENSION
+ : LocaleParserState::IGNORE_THE_REST;
+ break;
case 2:
case 3:
config->language[0] ? config->packRegion(start) : config->packLanguage(start);
@@ -2878,30 +2975,35 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool can
}
break;
default:
- return false;
+ state.parserState = LocaleParserState::IGNORE_THE_REST;
}
- return true;
+ return state;
}
void ResTable_config::setBcp47Locale(const char* in) {
locale = 0;
memset(localeScript, 0, sizeof(localeScript));
memset(localeVariant, 0, sizeof(localeVariant));
+ memset(localeNumberingSystem, 0, sizeof(localeNumberingSystem));
- const char* separator = in;
const char* start = in;
- while ((separator = strchr(start, '-')) != NULL) {
+ LocaleParserState state;
+ while (const char* separator = strchr(start, '-')) {
const size_t size = separator - start;
- if (!assignLocaleComponent(this, start, size)) {
- fprintf(stderr, "Invalid BCP-47 locale string: %s", in);
+ state = assignLocaleComponent(this, start, size, state);
+ if (state.parserState == LocaleParserState::IGNORE_THE_REST) {
+ fprintf(stderr, "Invalid BCP-47 locale string: %s\n", in);
+ break;
}
-
start = (separator + 1);
}
- const size_t size = in + strlen(in) - start;
- assignLocaleComponent(this, start, size);
+ if (state.parserState != LocaleParserState::IGNORE_THE_REST) {
+ const size_t size = strlen(start);
+ assignLocaleComponent(this, start, size, state);
+ }
+
localeScriptWasComputed = (localeScript[0] == '\0');
if (localeScriptWasComputed) {
computeScript();
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 854795559750..20d017813cf7 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1182,6 +1182,10 @@ struct ResTable_config
// tried but could not compute a script.
bool localeScriptWasComputed;
+ // The value of BCP 47 Unicode extension for key 'nu' (numbering system).
+ // Varies in length from 3 to 8 chars. Zero-filled value.
+ char localeNumberingSystem[8];
+
void copyFromDeviceNoSwap(const ResTable_config& o);
void copyFromDtoH(const ResTable_config& o);
@@ -1259,9 +1263,9 @@ struct ResTable_config
// variants, it will be a modified bcp47 tag: b+en+Latn+US.
void appendDirLocale(String8& str) const;
- // Sets the values of language, region, script and variant to the
- // well formed BCP-47 locale contained in |in|. The input locale is
- // assumed to be valid and no validation is performed.
+ // Sets the values of language, region, script, variant and numbering
+ // system to the well formed BCP 47 locale contained in |in|.
+ // The input locale is assumed to be valid and no validation is performed.
void setBcp47Locale(const char* in);
inline void clearLocale() {
@@ -1269,6 +1273,7 @@ struct ResTable_config
localeScriptWasComputed = false;
memset(localeScript, 0, sizeof(localeScript));
memset(localeVariant, 0, sizeof(localeVariant));
+ memset(localeNumberingSystem, 0, sizeof(localeNumberingSystem));
}
inline void computeScript() {
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 86a627e1485d..35007c815edd 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -185,6 +185,7 @@ TEST(ConfigLocaleTest, setLocale) {
EXPECT_TRUE(test.localeScriptWasComputed);
EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
EXPECT_EQ(0, test.localeVariant[0]);
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
test.setBcp47Locale("eng-419");
char out[4] = {1, 1, 1, 1};
@@ -198,6 +199,7 @@ TEST(ConfigLocaleTest, setLocale) {
EXPECT_EQ('4', out[0]);
EXPECT_EQ('1', out[1]);
EXPECT_EQ('9', out[2]);
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
test.setBcp47Locale("en-Latn-419");
EXPECT_EQ('e', test.language[0]);
@@ -209,6 +211,7 @@ TEST(ConfigLocaleTest, setLocale) {
EXPECT_EQ('4', out[0]);
EXPECT_EQ('1', out[1]);
EXPECT_EQ('9', out[2]);
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
test.setBcp47Locale("de-1901");
memset(out, 1, 4);
@@ -222,6 +225,7 @@ TEST(ConfigLocaleTest, setLocale) {
test.unpackRegion(out);
EXPECT_EQ('\0', out[0]);
EXPECT_EQ(0, strcmp("1901", test.localeVariant));
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
test.setBcp47Locale("de-Latn-1901");
memset(out, 1, 4);
@@ -235,6 +239,44 @@ TEST(ConfigLocaleTest, setLocale) {
test.unpackRegion(out);
EXPECT_EQ('\0', out[0]);
EXPECT_EQ(0, strcmp("1901", test.localeVariant));
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
+
+ test.setBcp47Locale("ar-EG-u-nu-latn");
+ EXPECT_EQ('a', test.language[0]);
+ EXPECT_EQ('r', test.language[1]);
+ EXPECT_EQ('E', test.country[0]);
+ EXPECT_EQ('G', test.country[1]);
+ EXPECT_TRUE(test.localeScriptWasComputed);
+ EXPECT_EQ(0, memcmp("Arab", test.localeScript, 4));
+ EXPECT_EQ(0, test.localeVariant[0]);
+ EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
+
+ test.setBcp47Locale("ar-EG-u");
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
+
+ test.setBcp47Locale("ar-EG-u-nu");
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
+
+ test.setBcp47Locale("ar-EG-u-attr-nu-latn");
+ EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
+
+ test.setBcp47Locale("ar-EG-u-ca-gregory-nu-latn");
+ EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
+
+ test.setBcp47Locale("ar-EG-u-nu-latn-ca-gregory");
+ EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
+
+ test.setBcp47Locale("ar-EG-u-nu-toolongnumsys");
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
+
+ test.setBcp47Locale("ar-EG-u-nu-latn-nu-arab");
+ EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
+
+ test.setBcp47Locale("ar-EG-u-co-nu-latn");
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
+
+ test.setBcp47Locale("ar-u-co-abcd-attr-nu-latn");
+ EXPECT_EQ(0, test.localeNumberingSystem[0]);
}
TEST(ConfigLocaleTest, computeScript) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 75967e9f6503..b2863921065a 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -84,57 +84,50 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
kTopLeft_GrSurfaceOrigin));
if (image) {
- // Convert imgTransform matrix from right to left handed coordinate system.
- // If we have a matrix transformation in right handed coordinate system
- //|ScaleX, SkewX, TransX| same transform in left handed is |ScaleX, SkewX, TransX |
- //|SkewY, ScaleY, TransY| |-SkewY, -ScaleY, 1-TransY|
- //|0, 0, 1 | |0, 0, 1 |
- SkMatrix textureMatrix;
- textureMatrix.setIdentity();
- textureMatrix[SkMatrix::kMScaleX] = imgTransform[Matrix4::kScaleX];
- textureMatrix[SkMatrix::kMScaleY] = -imgTransform[Matrix4::kScaleY];
- textureMatrix[SkMatrix::kMSkewX] = imgTransform[Matrix4::kSkewX];
- textureMatrix[SkMatrix::kMSkewY] = -imgTransform[Matrix4::kSkewY];
- textureMatrix[SkMatrix::kMTransX] = imgTransform[Matrix4::kTranslateX];
- textureMatrix[SkMatrix::kMTransY] = 1-imgTransform[Matrix4::kTranslateY];
-
- // textureMatrix maps 2D texture coordinates of the form (s, t, 1) with s and t in the
- // inclusive range [0, 1] to the texture (see GLConsumer::getTransformMatrix comments).
- // Convert textureMatrix to translate in real texture dimensions. Texture width and
- // height are affected by the orientation (width and height swapped for 90/270 rotation).
- if (textureMatrix[SkMatrix::kMSkewX] >= 0.5f || textureMatrix[SkMatrix::kMSkewX] <= -0.5f) {
- textureMatrix[SkMatrix::kMTransX] *= imgHeight;
- textureMatrix[SkMatrix::kMTransY] *= imgWidth;
- } else {
- textureMatrix[SkMatrix::kMTransX] *= imgWidth;
- textureMatrix[SkMatrix::kMTransY] *= imgHeight;
+ int displayedWidth = imgWidth, displayedHeight = imgHeight;
+ // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
+ // size.
+ if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
+ std::swap(displayedWidth, displayedHeight);
}
-
- // convert to Skia data structures
- SkRect skiaSrcRect = srcRect.toSkRect();
- SkMatrix textureMatrixInv;
SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
- bool srcNotEmpty = false;
- if (textureMatrix.invert(&textureMatrixInv)) {
- if (skiaSrcRect.isEmpty()) {
- skiaSrcRect = SkRect::MakeIWH(imgWidth, imgHeight);
- srcNotEmpty = !skiaSrcRect.isEmpty();
- } else {
- // src and dest rectangles need to be converted into texture coordinates before the
- // rotation matrix is applied (because drawImageRect preconcat its matrix).
- textureMatrixInv.mapRect(&skiaSrcRect);
- srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(imgWidth, imgHeight));
- }
- textureMatrixInv.mapRect(&skiaDestRect);
+ SkRect skiaSrcRect = srcRect.toSkRect();
+ if (skiaSrcRect.isEmpty()) {
+ skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
}
+ bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
if (srcNotEmpty) {
+ SkMatrix textureMatrixInv;
+ imgTransform.copyTo(textureMatrixInv);
+ //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // use bottom left origin and remove flipV and invert transformations.
+ SkMatrix flipV;
+ flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
+ textureMatrixInv.preConcat(flipV);
+ textureMatrixInv.preScale(1.0f/displayedWidth, 1.0f/displayedHeight);
+ textureMatrixInv.postScale(imgWidth, imgHeight);
+ SkMatrix textureMatrix;
+ if (!textureMatrixInv.invert(&textureMatrix)) {
+ textureMatrix = textureMatrixInv;
+ }
+
+ textureMatrixInv.mapRect(&skiaSrcRect);
+ textureMatrixInv.mapRect(&skiaDestRect);
+
// we render in an offscreen buffer to scale and to avoid an issue b/62262733
// with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
grContext.get(), SkBudgeted::kYes, bitmap->info());
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
+ // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
+ // is codified by tests using golden images like DecodeAccuracyTest.
+ if (skiaSrcRect.width() != bitmap->width()
+ || skiaSrcRect.height() != bitmap->height()) {
+ //TODO: apply filter always, but check if tests will be fine
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ }
scaledSurface->getCanvas()->concat(textureMatrix);
scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
SkCanvas::kFast_SrcRectConstraint);
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 10be6499417f..b8415b2e264b 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -66,7 +66,7 @@ public:
EncodedBuffer::iterator data();
bool flush(int fd);
- // Please don't use the following functions to dump protos unless you are sure about it.
+ // Please don't use the following functions to dump protos unless you are familiar with protobuf encoding.
void writeRawVarint(uint64_t varint);
void writeLengthDelimitedHeader(uint32_t id, size_t size);
void writeRawByte(uint8_t byte);
@@ -94,6 +94,7 @@ private:
inline void writeEnumImpl(uint32_t id, int val);
inline void writeBoolImpl(uint32_t id, bool val);
inline void writeUtf8StringImpl(uint32_t id, const char* val, size_t size);
+ inline void writeMessageBytesImpl(uint32_t id, const char* val, size_t size);
bool compact();
size_t editEncodedSize(size_t rawSize);
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 9dadf1c20510..b91e3db0e39c 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -234,6 +234,10 @@ ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
case TYPE_BYTES:
writeUtf8StringImpl(id, val, size);
return true;
+ case TYPE_MESSAGE:
+ // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
+ writeMessageBytesImpl(id, val, size);
+ return true;
default:
ALOGW("Field type %d is not supported when writing char[] val.",
(int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
@@ -678,6 +682,16 @@ ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size
}
}
+inline void
+ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
+{
+ if (val == NULL) return;
+ writeLengthDelimitedHeader(id, size);
+ for (size_t i=0; i<size; i++) {
+ mBuffer.writeRawByte(val[i]);
+ }
+}
+
} // util
} // android
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index ed5f7d848663..c475e122833a 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -96,6 +96,19 @@ import java.util.Map;
* <tr><td>{@link #KEY_MIME}</td><td>String</td><td>The type of the format.</td></tr>
* <tr><td>{@link #KEY_LANGUAGE}</td><td>String</td><td>The language of the content.</td></tr>
* </table>
+ *
+ * Image formats have the following keys:
+ * <table>
+ * <tr><td>{@link #KEY_MIME}</td><td>String</td><td>The type of the format.</td></tr>
+ * <tr><td>{@link #KEY_WIDTH}</td><td>Integer</td><td></td></tr>
+ * <tr><td>{@link #KEY_HEIGHT}</td><td>Integer</td><td></td></tr>
+ * <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td>set by the user
+ * for encoders, readable in the output format of decoders</b></td></tr>
+ * <tr><td>{@link #KEY_GRID_WIDTH}</td><td>Integer</td><td>required if the image has grid</td></tr>
+ * <tr><td>{@link #KEY_GRID_HEIGHT}</td><td>Integer</td><td>required if the image has grid</td></tr>
+ * <tr><td>{@link #KEY_GRID_ROWS}</td><td>Integer</td><td>required if the image has grid</td></tr>
+ * <tr><td>{@link #KEY_GRID_COLS}</td><td>Integer</td><td>required if the image has grid</td></tr>
+ * </table>
*/
public final class MediaFormat {
public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
@@ -126,6 +139,35 @@ public final class MediaFormat {
public static final String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
/**
+ * MIME type for HEIF still image data encoded in HEVC.
+ *
+ * To decode such an image, {@link MediaCodec} decoder for
+ * {@ #MIMETYPE_VIDEO_HEVC} shall be used. The client needs to form
+ * the correct {@link #MediaFormat} based on additional information in
+ * the track format, and send it to {@link MediaCodec#configure}.
+ *
+ * The track's MediaFormat will come with {@link #KEY_WIDTH} and
+ * {@link #KEY_HEIGHT} keys, which describes the width and height
+ * of the image. If the image doesn't contain grid (i.e. none of
+ * {@link #KEY_GRID_WIDTH}, {@link #KEY_GRID_HEIGHT},
+ * {@link #KEY_GRID_ROWS}, {@link #KEY_GRID_COLS} are present}), the
+ * track will contain a single sample of coded data for the entire image,
+ * and the image width and height should be used to set up the decoder.
+ *
+ * If the image does come with grid, each sample from the track will
+ * contain one tile in the grid, of which the size is described by
+ * {@link #KEY_GRID_WIDTH} and {@link #KEY_GRID_HEIGHT}. This size
+ * (instead of {@link #KEY_WIDTH} and {@link #KEY_HEIGHT}) should be
+ * used to set up the decoder. The track contains {@link #KEY_GRID_ROWS}
+ * by {@link #KEY_GRID_COLS} samples in row-major, top-row first,
+ * left-to-right order. The output image should be reconstructed by
+ * first tiling the decoding results of the tiles in the correct order,
+ * then trimming (before rotation is applied) on the bottom and right
+ * side, if the tiled area is larger than the image width and height.
+ */
+ public static final String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
+
+ /**
* MIME type for WebVTT subtitle data.
*/
public static final String MIMETYPE_TEXT_VTT = "text/vtt";
@@ -232,6 +274,54 @@ public final class MediaFormat {
public static final String KEY_FRAME_RATE = "frame-rate";
/**
+ * A key describing the grid width of the content in a {@link #MIMETYPE_IMAGE_ANDROID_HEIC}
+ * track. The associated value is an integer.
+ *
+ * Refer to {@link #MIMETYPE_IMAGE_ANDROID_HEIC} on decoding instructions of such tracks.
+ *
+ * @see #KEY_GRID_HEIGHT
+ * @see #KEY_GRID_ROWS
+ * @see #KEY_GRID_COLS
+ */
+ public static final String KEY_GRID_WIDTH = "grid-width";
+
+ /**
+ * A key describing the grid height of the content in a {@link #MIMETYPE_IMAGE_ANDROID_HEIC}
+ * track. The associated value is an integer.
+ *
+ * Refer to {@link #MIMETYPE_IMAGE_ANDROID_HEIC} on decoding instructions of such tracks.
+ *
+ * @see #KEY_GRID_WIDTH
+ * @see #KEY_GRID_ROWS
+ * @see #KEY_GRID_COLS
+ */
+ public static final String KEY_GRID_HEIGHT = "grid-height";
+
+ /**
+ * A key describing the number of grid rows in the content in a
+ * {@link #MIMETYPE_IMAGE_ANDROID_HEIC} track. The associated value is an integer.
+ *
+ * Refer to {@link #MIMETYPE_IMAGE_ANDROID_HEIC} on decoding instructions of such tracks.
+ *
+ * @see #KEY_GRID_WIDTH
+ * @see #KEY_GRID_HEIGHT
+ * @see #KEY_GRID_COLS
+ */
+ public static final String KEY_GRID_ROWS = "grid-rows";
+
+ /**
+ * A key describing the number of grid columns in the content in a
+ * {@link #MIMETYPE_IMAGE_ANDROID_HEIC} track. The associated value is an integer.
+ *
+ * Refer to {@link #MIMETYPE_IMAGE_ANDROID_HEIC} on decoding instructions of such tracks.
+ *
+ * @see #KEY_GRID_WIDTH
+ * @see #KEY_GRID_HEIGHT
+ * @see #KEY_GRID_ROWS
+ */
+ public static final String KEY_GRID_COLS = "grid-cols";
+
+ /**
* A key describing the raw audio sample encoding/format.
*
* <p>The associated value is an integer, using one of the
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 760cc49bc1e2..0b8640184ff5 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -47,7 +47,7 @@ public class MediaMetadataRetriever
// The field below is accessed by native methods
@SuppressWarnings("unused")
private long mNativeContext;
-
+
private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
public MediaMetadataRetriever() {
@@ -58,7 +58,7 @@ public class MediaMetadataRetriever
* Sets the data source (file pathname) to use. Call this
* method before the rest of the methods in this class. This method may be
* time-consuming.
- *
+ *
* @param path The path of the input media file.
* @throws IllegalArgumentException If the path is invalid.
*/
@@ -113,7 +113,7 @@ public class MediaMetadataRetriever
* responsibility to close the file descriptor. It is safe to do so as soon
* as this call returns. Call this method before the rest of the methods in
* this class. This method may be time-consuming.
- *
+ *
* @param fd the FileDescriptor for the file you want to play
* @param offset the offset into the file where the data to be played starts,
* in bytes. It must be non-negative
@@ -123,13 +123,13 @@ public class MediaMetadataRetriever
*/
public native void setDataSource(FileDescriptor fd, long offset, long length)
throws IllegalArgumentException;
-
+
/**
* Sets the data source (FileDescriptor) to use. It is the caller's
* responsibility to close the file descriptor. It is safe to do so as soon
* as this call returns. Call this method before the rest of the methods in
* this class. This method may be time-consuming.
- *
+ *
* @param fd the FileDescriptor for the file you want to play
* @throws IllegalArgumentException if the FileDescriptor is invalid
*/
@@ -138,11 +138,11 @@ public class MediaMetadataRetriever
// intentionally less than LONG_MAX
setDataSource(fd, 0, 0x7ffffffffffffffL);
}
-
+
/**
- * Sets the data source as a content Uri. Call this method before
+ * Sets the data source as a content Uri. Call this method before
* the rest of the methods in this class. This method may be time-consuming.
- *
+ *
* @param context the Context to use when resolving the Uri
* @param uri the Content URI of the data you want to play
* @throws IllegalArgumentException if the Uri is invalid
@@ -154,7 +154,7 @@ public class MediaMetadataRetriever
if (uri == null) {
throw new IllegalArgumentException();
}
-
+
String scheme = uri.getScheme();
if(scheme == null || scheme.equals("file")) {
setDataSource(uri.getPath());
@@ -213,12 +213,12 @@ public class MediaMetadataRetriever
/**
* Call this method after setDataSource(). This method retrieves the
* meta data value associated with the keyCode.
- *
+ *
* The keyCode currently supported is listed below as METADATA_XXX
* constants. With any other value, it returns a null pointer.
- *
+ *
* @param keyCode One of the constants listed below at the end of the class.
- * @return The meta data value associate with the given keyCode on success;
+ * @return The meta data value associate with the given keyCode on success;
* null on failure.
*/
public native String extractMetadata(int keyCode);
@@ -357,6 +357,109 @@ public class MediaMetadataRetriever
private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
/**
+ * This method retrieves a video frame by its index. It should only be called
+ * after {@link #setDataSource}.
+ *
+ * @param frameIndex 0-based index of the video frame. The frame index must be that of
+ * a valid frame. The total number of frames available for retrieval can be queried
+ * via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
+ *
+ * @throws IllegalStateException if the container doesn't contain video or image sequences.
+ * @throws IllegalArgumentException if the requested frame index does not exist.
+ *
+ * @return A Bitmap containing the requested video frame, or null if the retrieval fails.
+ *
+ * @see #getFramesAtIndex(int, int)
+ */
+ public Bitmap getFrameAtIndex(int frameIndex) {
+ Bitmap[] bitmaps = getFramesAtIndex(frameIndex, 1);
+ if (bitmaps == null || bitmaps.length < 1) {
+ return null;
+ }
+ return bitmaps[0];
+ }
+
+ /**
+ * This method retrieves a consecutive set of video frames starting at the
+ * specified index. It should only be called after {@link #setDataSource}.
+ *
+ * If the caller intends to retrieve more than one consecutive video frames,
+ * this method is preferred over {@link #getFrameAtIndex(int)} for efficiency.
+ *
+ * @param frameIndex 0-based index of the first video frame to retrieve. The frame index
+ * must be that of a valid frame. The total number of frames available for retrieval
+ * can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
+ * @param numFrames number of consecutive video frames to retrieve. Must be a positive
+ * value. The stream must contain at least numFrames frames starting at frameIndex.
+ *
+ * @throws IllegalStateException if the container doesn't contain video or image sequences.
+ * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
+ * stream doesn't contain at least numFrames starting at frameIndex.
+
+ * @return An array of Bitmaps containing the requested video frames. The returned
+ * array could contain less frames than requested if the retrieval fails.
+ *
+ * @see #getFrameAtIndex(int)
+ */
+ public Bitmap[] getFramesAtIndex(int frameIndex, int numFrames) {
+ if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
+ throw new IllegalStateException("Does not contail video or image sequences");
+ }
+ int frameCount = Integer.parseInt(
+ extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT));
+ if (frameIndex < 0 || numFrames < 1
+ || frameIndex >= frameCount
+ || frameIndex > frameCount - numFrames) {
+ throw new IllegalArgumentException("Invalid frameIndex or numFrames: "
+ + frameIndex + ", " + numFrames);
+ }
+ return _getFrameAtIndex(frameIndex, numFrames);
+ }
+ private native Bitmap[] _getFrameAtIndex(int frameIndex, int numFrames);
+
+ /**
+ * This method retrieves a still image by its index. It should only be called
+ * after {@link #setDataSource}.
+ *
+ * @param imageIndex 0-based index of the image, with negative value indicating
+ * the primary image.
+ * @throws IllegalStateException if the container doesn't contain still images.
+ * @throws IllegalArgumentException if the requested image does not exist.
+ *
+ * @return the requested still image, or null if the image cannot be retrieved.
+ *
+ * @see #getPrimaryImage
+ */
+ public Bitmap getImageAtIndex(int imageIndex) {
+ if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
+ throw new IllegalStateException("Does not contail still images");
+ }
+
+ String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT);
+ if (imageIndex >= Integer.parseInt(imageCount)) {
+ throw new IllegalArgumentException("Invalid image index: " + imageCount);
+ }
+
+ return _getImageAtIndex(imageIndex);
+ }
+
+ /**
+ * This method retrieves the primary image of the media content. It should only
+ * be called after {@link #setDataSource}.
+ *
+ * @return the primary image, or null if it cannot be retrieved.
+ *
+ * @throws IllegalStateException if the container doesn't contain still images.
+ *
+ * @see #getImageAtIndex(int)
+ */
+ public Bitmap getPrimaryImage() {
+ return getImageAtIndex(-1);
+ }
+
+ private native Bitmap _getImageAtIndex(int imageIndex);
+
+ /**
* Call this method after setDataSource(). This method finds the optional
* graphic or album/cover art associated associated with the data source. If
* there are more than one pictures, (any) one of them is returned.
@@ -572,5 +675,40 @@ public class MediaMetadataRetriever
* number.
*/
public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25;
+ /**
+ * If this key exists the media contains still image content.
+ */
+ public static final int METADATA_KEY_HAS_IMAGE = 26;
+ /**
+ * If the media contains still images, this key retrieves the number
+ * of still images.
+ */
+ public static final int METADATA_KEY_IMAGE_COUNT = 27;
+ /**
+ * If the media contains still images, this key retrieves the image
+ * index of the primary image.
+ */
+ public static final int METADATA_KEY_IMAGE_PRIMARY = 28;
+ /**
+ * If the media contains still images, this key retrieves the width
+ * of the primary image.
+ */
+ public static final int METADATA_KEY_IMAGE_WIDTH = 29;
+ /**
+ * If the media contains still images, this key retrieves the height
+ * of the primary image.
+ */
+ public static final int METADATA_KEY_IMAGE_HEIGHT = 30;
+ /**
+ * If the media contains still images, this key retrieves the rotation
+ * of the primary image.
+ */
+ public static final int METADATA_KEY_IMAGE_ROTATION = 31;
+ /**
+ * If the media contains video and this key exists, it retrieves the
+ * total number of frames in the video sequence.
+ */
+ public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
+
// Add more here...
}
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 4659ae131f53..42ebf6ab8cfc 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -244,29 +244,9 @@ static void rotate(T *dst, const T *src, size_t width, size_t height, int angle)
}
}
-static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
- JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
-{
- ALOGV("getFrameAtTime: %lld us option: %d dst width: %d heigh: %d",
- (long long)timeUs, option, dst_width, dst_height);
- MediaMetadataRetriever* retriever = getRetriever(env, thiz);
- if (retriever == 0) {
- jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
- return NULL;
- }
-
- // Call native method to retrieve a video frame
- VideoFrame *videoFrame = NULL;
- sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option);
- if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
- videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
- }
- if (videoFrame == NULL) {
- ALOGE("getFrameAtTime: videoFrame is a NULL pointer");
- return NULL;
- }
-
- ALOGV("Dimension = %dx%d and bytes = %d",
+static jobject getBitmapFromVideoFrame(
+ JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height) {
+ ALOGV("getBitmapFromVideoFrame: dimension = %dx%d and bytes = %d",
videoFrame->mDisplayWidth,
videoFrame->mDisplayHeight,
videoFrame->mSize);
@@ -301,7 +281,7 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
if (env->ExceptionCheck()) {
env->ExceptionClear();
}
- ALOGE("getFrameAtTime: create Bitmap failed!");
+ ALOGE("getBitmapFromVideoFrame: create Bitmap failed!");
return NULL;
}
@@ -340,6 +320,93 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
return jBitmap;
}
+static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
+ JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
+{
+ ALOGV("getFrameAtTime: %lld us option: %d dst width: %d heigh: %d",
+ (long long)timeUs, option, dst_width, dst_height);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return NULL;
+ }
+
+ // Call native method to retrieve a video frame
+ VideoFrame *videoFrame = NULL;
+ sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option);
+ if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
+ videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+ }
+ if (videoFrame == NULL) {
+ ALOGE("getFrameAtTime: videoFrame is a NULL pointer");
+ return NULL;
+ }
+
+ return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height);
+}
+
+static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
+ JNIEnv *env, jobject thiz, jint index)
+{
+ ALOGV("getImageAtIndex: index %d", index);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return NULL;
+ }
+
+ // Call native method to retrieve an image
+ VideoFrame *videoFrame = NULL;
+ sp<IMemory> frameMemory = retriever->getImageAtIndex(index);
+ if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
+ videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+ }
+ if (videoFrame == NULL) {
+ ALOGE("getImageAtIndex: videoFrame is a NULL pointer");
+ return NULL;
+ }
+
+ return getBitmapFromVideoFrame(env, videoFrame, -1, -1);
+}
+
+static jobjectArray android_media_MediaMetadataRetriever_getFrameAtIndex(
+ JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames)
+{
+ ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d", frameIndex, numFrames);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env,
+ "java/lang/IllegalStateException", "No retriever available");
+ return NULL;
+ }
+
+ std::vector<sp<IMemory> > frames;
+ status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames);
+ if (err != OK || frames.size() == 0) {
+ ALOGE("failed to get frames from retriever, err=%d, size=%zu",
+ err, frames.size());
+ return NULL;
+ }
+
+ jobjectArray bitmapArrayObj = env->NewObjectArray(
+ frames.size(), fields.bitmapClazz, NULL);
+ if (bitmapArrayObj == NULL) {
+ ALOGE("can't create bitmap array object");
+ return NULL;
+ }
+
+ for (size_t i = 0; i < frames.size(); i++) {
+ if (frames[i] == NULL || frames[i]->pointer() == NULL) {
+ ALOGE("video frame at index %zu is a NULL pointer", frameIndex + i);
+ continue;
+ }
+ VideoFrame *videoFrame = static_cast<VideoFrame *>(frames[i]->pointer());
+ jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1);
+ env->SetObjectArrayElement(bitmapArrayObj, i, bitmapObj);
+ }
+ return bitmapArrayObj;
+}
+
static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
JNIEnv *env, jobject thiz, jint pictureType)
{
@@ -485,6 +552,8 @@ static const JNINativeMethod nativeMethods[] = {
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
{"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
+ {"_getImageAtIndex", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getImageAtIndex},
+ {"_getFrameAtIndex", "(II)[Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtIndex},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
{"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 0da628917713..fe2a939b58a6 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -955,6 +955,7 @@ void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize)
outThumbSize = image_data.thumbnail.length;
} else {
free(result);
+ result = NULL;
}
}
break;
diff --git a/packages/SettingsLib/res/drawable/ic_bt_laptop.xml b/packages/SettingsLib/res/drawable/ic_bt_laptop.xml
new file mode 100644
index 000000000000..029e4d913434
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_laptop.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,18c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0
+ -2,0.9 -2,2v10c0,1.1 0.9,2 2,2H0v2h24v-2h-4zM4,6h16v10H4V6z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml b/packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml
new file mode 100644
index 000000000000..6e32e1a7f631
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.5,12l3.8,-3.7c0.4,-0.4 0.4,-1.1 0,-1.5l-4.5,-4.5c-0.4,-0.4 -1.1,-0.4 -1.5,0.1C11.1,2.5 11,2.8 11,3v6.4L6.9,5.4C6.5,5 5.9,5 5.5,5.4s-0.4,1.1 0,1.5l5.1,5.1l-5.1,5.1c-0.4,0.4 -0.4,1.1 0,1.5s1.1,0.4 1.5,0l4.1,-4V21c0,0.6 0.5,1 1,1c0.3,0 0.5,-0.1 0.7,-0.3l0.1,0l4.5,-4.5c0.4,-0.4 0.4,-1.1 0,-1.5L13.5,12zM13,9.7V5.4l2.1,2.2L13,9.7zM13,18.6v-4.3l2.1,2.2L13,18.6z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_settings_print.xml b/packages/SettingsLib/res/drawable/ic_settings_print.xml
new file mode 100644
index 000000000000..0eab4021956b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_settings_print.xml
@@ -0,0 +1,28 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19,8H5c-1.66,0-3,1.34-3,3v5c0,0.55,0.45,1,1,1h3v3c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1v-3h3c0.55,0,1-0.45,1-1v-5
+C22,9.34,20.66,8,19,8z M16,19H8v-5h8V19z
+M19,12c-0.55,0-1-0.45-1-1s0.45-1,1-1s1,0.45,1,1S19.55,12,19,12z M17,3H7
+C6.45,3,6,3.45,6,4v3h12V4C18,3.45,17.55,3,17,3z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9318a7f62769..f45532432214 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -210,7 +210,7 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"აირჩიეთ Bluetooth აუდიოს LDAC კოდეკის\nდაკვრის ხარისხი"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"სტრიმინგი: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="dns_tls" msgid="6773814174391131955">"DNS-ის TLS-ის მეშვეობით გადაცემა"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"ჩართვის შემთხვევაში, ცადეთ DNS-ის TLS-ის მეშვეობით გადაცემა პორტზე 853."</string>
+ <string name="dns_tls_summary" msgid="3692494150251071380">"ჩართვის შემთხვევაში, DNS-ის TLS-ის მეშვეობით გადაცემის ცდა, პორტზე 853."</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ჩართვის შემთხვევაში, Wi‑Fi უფრო აქტიურად შეეცდება მობილურ ინტერნეტზე გადართვას, როცა Wi‑Fi სიგნალი სუსტია"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 725665dcc09b..d88adeac21c3 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -295,7 +295,7 @@
<string name="app_process_limit_title" msgid="4280600650253107163">"Лимит фоновых процессов"</string>
<string name="show_all_anrs" msgid="28462979638729082">"Все ANR"</string>
<string name="show_all_anrs_summary" msgid="641908614413544127">"Уведомлять о том, что приложение не отвечает"</string>
- <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Показывать предупреждения канала передачи оповещения"</string>
+ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Показывать предупреждения канала передачи уведомлений"</string>
<string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Показывать предупреждение о новых уведомлениях приложения вне допустимого канала"</string>
<string name="force_allow_on_external" msgid="3215759785081916381">"Разрешить сохранение на внешние накопители"</string>
<string name="force_allow_on_external_summary" msgid="3640752408258034689">"Разрешить сохранение приложений на внешних накопителях (независимо от значений в манифесте)"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a404759d0639..360848f72ddd 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -235,6 +235,27 @@
<!-- Message for the error dialog when BT pairing fails because the other device rejected the pairing. -->
<string name="bluetooth_pairing_rejected_error_message">Pairing rejected by <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=4875089335641234463] -->
+ <string name="bluetooth_talkback_computer">Computer</string>
+
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=5140152177885220949] -->
+ <string name="bluetooth_talkback_headset">Headset</string>
+
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=4260255181240622896] -->
+ <string name="bluetooth_talkback_phone">Phone</string>
+
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=551146170554589119] -->
+ <string name="bluetooth_talkback_imaging">Imaging</string>
+
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=26580326066627664] -->
+ <string name="bluetooth_talkback_headphone">Headphone</string>
+
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=5165842622743212268] -->
+ <string name="bluetooth_talkback_input_peripheral">Input Peripheral</string>
+
+ <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=5615463912185280812] -->
+ <string name="bluetooth_talkback_bluetooth">Bluetooth</string>
+
<!-- Content description of the WIFI signal when WIFI is disabled for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wifi_off">Wifi off.</string>
<!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 7bda2314f4c4..3299cb2d1221 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -32,7 +32,7 @@ import java.util.List;
/**
* PanProfile handles Bluetooth PAN profile (NAP and PANU).
*/
-public final class PanProfile implements LocalBluetoothProfile {
+public class PanProfile implements LocalBluetoothProfile {
private static final String TAG = "PanProfile";
private static boolean V = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
index c9194268543a..0ee1dad9d744 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
@@ -1,9 +1,17 @@
package com.android.settingslib.bluetooth;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.util.Pair;
import com.android.settingslib.R;
+import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
+
+import java.util.List;
public class Utils {
public static final boolean V = false; // verbose logging
@@ -40,4 +48,78 @@ public class Utils {
void onShowError(Context context, String name, int messageResId);
}
+ public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
+ CachedBluetoothDevice cachedDevice) {
+ return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */);
+ }
+
+ public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
+ CachedBluetoothDevice cachedDevice, float iconScale) {
+ BluetoothClass btClass = cachedDevice.getBtClass();
+ final int level = cachedDevice.getBatteryLevel();
+ if (btClass != null) {
+ switch (btClass.getMajorDeviceClass()) {
+ case BluetoothClass.Device.Major.COMPUTER:
+ return new Pair<>(getBluetoothDrawable(context, R.drawable.ic_bt_laptop, level,
+ iconScale),
+ context.getString(R.string.bluetooth_talkback_computer));
+
+ case BluetoothClass.Device.Major.PHONE:
+ return new Pair<>(
+ getBluetoothDrawable(context, R.drawable.ic_bt_cellphone, level,
+ iconScale),
+ context.getString(R.string.bluetooth_talkback_phone));
+
+ case BluetoothClass.Device.Major.PERIPHERAL:
+ return new Pair<>(
+ getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass),
+ level, iconScale),
+ context.getString(R.string.bluetooth_talkback_input_peripheral));
+
+ case BluetoothClass.Device.Major.IMAGING:
+ return new Pair<>(
+ getBluetoothDrawable(context, R.drawable.ic_settings_print, level,
+ iconScale),
+ context.getString(R.string.bluetooth_talkback_imaging));
+
+ default:
+ // unrecognized device class; continue
+ }
+ }
+
+ List<LocalBluetoothProfile> profiles = cachedDevice.getProfiles();
+ for (LocalBluetoothProfile profile : profiles) {
+ int resId = profile.getDrawableResource(btClass);
+ if (resId != 0) {
+ return new Pair<>(getBluetoothDrawable(context, resId, level, iconScale), null);
+ }
+ }
+ if (btClass != null) {
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+ return new Pair<>(
+ getBluetoothDrawable(context, R.drawable.ic_bt_headset_hfp, level,
+ iconScale),
+ context.getString(R.string.bluetooth_talkback_headset));
+ }
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
+ return new Pair<>(
+ getBluetoothDrawable(context, R.drawable.ic_bt_headphones_a2dp, level,
+ iconScale),
+ context.getString(R.string.bluetooth_talkback_headphone));
+ }
+ }
+ return new Pair<>(
+ getBluetoothDrawable(context, R.drawable.ic_settings_bluetooth, level, iconScale),
+ context.getString(R.string.bluetooth_talkback_bluetooth));
+ }
+
+ public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId,
+ int batteryLevel, float iconScale) {
+ if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel,
+ iconScale);
+ } else {
+ return context.getDrawable(resId);
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index b1dbb0af54a7..4091ce1f173e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -59,7 +59,7 @@ public class CachedBluetoothDeviceTest {
@Mock
private A2dpProfile mA2dpProfile;
@Mock
- private HidProfile mHidProfile;
+ private PanProfile mPanProfile;
@Mock
private BluetoothDevice mDevice;
private CachedBluetoothDevice mCachedDevice;
@@ -74,7 +74,7 @@ public class CachedBluetoothDeviceTest {
when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
when(mHfpProfile.isProfileReady()).thenReturn(true);
when(mA2dpProfile.isProfileReady()).thenReturn(true);
- when(mHidProfile.isProfileReady()).thenReturn(true);
+ when(mPanProfile.isProfileReady()).thenReturn(true);
mCachedDevice = spy(
new CachedBluetoothDevice(mContext, mAdapter, mProfileManager, mDevice));
doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
@@ -92,37 +92,37 @@ public class CachedBluetoothDeviceTest {
@Test
public void testGetConnectionSummary_testSingleProfileConnectDisconnect() {
// Test without battery level
- // Set HID profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+ // Set PAN profile to be connected and test connection state summary
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
R.string.bluetooth_connected));
- // Set HID profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+ // Set PAN profile to be disconnected and test connection state summary
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Test with battery level
mBatteryLevel = 10;
- // Set HID profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+ // Set PAN profile to be connected and test connection state summary
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
R.string.bluetooth_connected_battery_level,
com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
- // Set HID profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+ // Set PAN profile to be disconnected and test connection state summary
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
- // Set HID profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+ // Set PAN profile to be connected and test connection state summary
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
R.string.bluetooth_connected));
- // Set HID profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+ // Set PAN profile to be disconnected and test connection state summary
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@@ -130,10 +130,10 @@ public class CachedBluetoothDeviceTest {
public void testGetConnectionSummary_testMultipleProfileConnectDisconnect() {
mBatteryLevel = 10;
- // Set HFP, A2DP and HID profile to be connected and test connection state summary
+ // Set HFP, A2DP and PAN profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
R.string.bluetooth_connected_battery_level,
com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
@@ -158,7 +158,7 @@ public class CachedBluetoothDeviceTest {
com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
// Disconnect all profiles and test connection state summary
- mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+ mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java
new file mode 100644
index 000000000000..5eb543ba3bae
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothDevice;
+import android.graphics.drawable.Drawable;
+
+import com.android.settingslib.R;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
+import com.android.settingslib.testutils.shadow.SettingsLibShadowResources;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+ shadows = SettingsLibShadowResources.class)
+public class UtilsTest {
+
+ @Test
+ public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() {
+ final Drawable drawable = Utils.getBluetoothDrawable(RuntimeEnvironment.application,
+ R.drawable.ic_bt_laptop, BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */);
+
+ assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class);
+ }
+
+ @Test
+ public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() {
+ final Drawable drawable = Utils.getBluetoothDrawable(RuntimeEnvironment.application,
+ R.drawable.ic_bt_laptop, 10 /* batteryLevel */, 1 /* iconScale */);
+
+ assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class);
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index d311ba87d5fb..527122873f23 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Upišite lozinku za otključavanje"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Upišite PIN za otključavanje"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Pogrešan PIN."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Nevažeća kartica."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Napunjeno"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Punjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Brzo punjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index c706900e21d3..9b48a4b1b564 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"잠금 해제하려면 비밀번호 입력"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"잠금 해제하려면 PIN 입력"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"잘못된 PIN 코드입니다."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"유효하지 않은 카드"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"충전됨"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"충전 중"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"고속 충전 중"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 2c33c98b0dba..59f441290208 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Wpisz hasło, aby odblokować"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Wpisz kod PIN, aby odblokować"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nieprawidłowy kod PIN."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Nieprawidłowa karta."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Naładowana"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Ładowanie"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Szybkie ładowanie"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 4855161d45d3..0ba941cd59d4 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"திறக்க, கடவுச்சொல்லை உள்ளிடவும்"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"திறக்க, பின்னை உள்ளிடவும்"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"தவறான பின் குறியீடு."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"செல்லாத சிம் கார்டு."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"சார்ஜ் செய்யப்பட்டது"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"சார்ஜ் ஆகிறது"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"வேகமாகச் சார்ஜாகிறது"</string>
diff --git a/packages/SystemUI/res/layout/operator_name.xml b/packages/SystemUI/res/layout/operator_name.xml
new file mode 100644
index 000000000000..c4f75e927604
--- /dev/null
+++ b/packages/SystemUI/res/layout/operator_name.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/operator_name_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ >
+ <com.android.systemui.statusbar.OperatorNameView
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:maxLength="20"
+ android:gravity="center_vertical|start"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true" />
+</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index c6452c03459a..6de27acd741b 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -48,6 +48,11 @@
android:paddingEnd="8dp"
android:orientation="horizontal"
>
+ <ViewStub
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout="@layout/operator_name" />
<!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index f9a423527db5..5d621cb79fc4 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -701,7 +701,7 @@
<string name="accessibility_action_divider_top_70" msgid="5090779195650364522">"Gore 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="6385859741925078668">"Gore 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="6201455163864841205">"Gore 30%"</string>
- <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"Dole cijeli ekran"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"Donji ekran kao cijeli ekran"</string>
<string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite za uređivanje."</string>
<string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> Dvaput dodirnite za dodavanje."</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>. Dvaput dodirnite za odabir."</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 296842f86fa3..27d5f1b89868 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -233,8 +233,8 @@
<string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode kerja aktif."</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Mode kerja dinonaktifkan."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Mode kerja diaktifkan."</string>
- <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Penghemat Data nonaktif."</string>
- <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Penghemat Data diaktifkan."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Penghemat Kuota Internet nonaktif."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Penghemat Kuota Internet diaktifkan."</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan tampilan"</string>
<string name="accessibility_ambient_display_charging" msgid="9084521679384069087">"Mengisi daya"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
@@ -636,9 +636,9 @@
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphone terhubung"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset terhubung"</string>
- <string name="data_saver" msgid="5037565123367048522">"Penghemat Data"</string>
- <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Penghemat Data aktif"</string>
- <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Penghemat Data nonaktif"</string>
+ <string name="data_saver" msgid="5037565123367048522">"Penghemat Kuota Internet"</string>
+ <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Penghemat Kuota Internet aktif"</string>
+ <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Penghemat Kuota Internet nonaktif"</string>
<string name="switch_bar_on" msgid="1142437840752794229">"Aktif"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Nonaktif"</string>
<string name="nav_bar" msgid="1993221402773877607">"Bilah navigasi"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0fe81d9dfef1..f54115b0c9e2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -301,6 +301,9 @@
<!-- Enable the default volume dialog -->
<bool name="enable_volume_ui">true</bool>
+ <!-- Whether to show operator name in the status bar -->
+ <bool name="config_showOperatorNameInStatusBar">false</bool>
+
<!-- Duration of the full carrier network change icon animation. -->
<integer name="carrier_network_change_anim_time">3000</integer>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2bb992c449b6..282a71bb96ca 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1738,6 +1738,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mFailedAttempts.delete(sCurrentUser);
}
+ public ServiceState getServiceState(int subId) {
+ return mServiceStates.get(subId);
+ }
+
public int getFailedUnlockAttempts(int userId) {
return mFailedAttempts.get(userId, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/DemoMode.java b/packages/SystemUI/src/com/android/systemui/DemoMode.java
index 11996d078bc3..5c3971571b87 100644
--- a/packages/SystemUI/src/com/android/systemui/DemoMode.java
+++ b/packages/SystemUI/src/com/android/systemui/DemoMode.java
@@ -37,4 +37,5 @@ public interface DemoMode {
public static final String COMMAND_STATUS = "status";
public static final String COMMAND_NOTIFICATIONS = "notifications";
public static final String COMMAND_VOLUME = "volume";
+ public static final String COMMAND_OPERATOR = "operator";
}
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 44a044bc4ce4..880ae709b59d 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -28,7 +28,7 @@ public interface RecentsComponent {
/**
* Docks the top-most task and opens recents.
*/
- boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds,
+ boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds,
int metricsDockAction);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
index e6d6c5586ad8..db4f988a9122 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -18,6 +18,8 @@ package com.android.systemui.pip.phone;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -77,7 +79,8 @@ public class InputConsumerController {
}
}
- private IWindowManager mWindowManager;
+ private final IWindowManager mWindowManager;
+ private final IBinder mToken;
private PipInputEventReceiver mInputEventReceiver;
private TouchListener mListener;
@@ -85,6 +88,7 @@ public class InputConsumerController {
public InputConsumerController(IWindowManager windowManager) {
mWindowManager = windowManager;
+ mToken = new Binder();
registerInputConsumer();
}
@@ -122,7 +126,7 @@ public class InputConsumerController {
final InputChannel inputChannel = new InputChannel();
try {
mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
- mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel);
+ mWindowManager.createInputConsumer(mToken, INPUT_CONSUMER_PIP, inputChannel);
} catch (RemoteException e) {
Log.e(TAG, "Failed to create PIP input consumer", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 1aecdceb378c..0e4a9fe32911 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -134,7 +134,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
if (lastDevice != null) {
int batteryLevel = lastDevice.getBatteryLevel();
if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- state.icon = new BluetoothBatteryTileIcon(batteryLevel,
+ state.icon = new BluetoothBatteryTileIcon(lastDevice,
mContext.getResources().getFraction(
R.fraction.bt_battery_scale_fraction, 1, 1));
}
@@ -213,18 +213,19 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
}
private class BluetoothBatteryTileIcon extends Icon {
- private int mLevel;
private float mIconScale;
+ private CachedBluetoothDevice mDevice;
- BluetoothBatteryTileIcon(int level, float iconScale) {
- mLevel = level;
+ BluetoothBatteryTileIcon(CachedBluetoothDevice device, float iconScale) {
mIconScale = iconScale;
+ mDevice = device;
}
@Override
public Drawable getDrawable(Context context) {
- return createLayerDrawable(context,
- R.drawable.ic_qs_bluetooth_connected, mLevel, mIconScale);
+ // This method returns Pair<Drawable, String> while first value is the drawable
+ return com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription(
+ context, mDevice, mIconScale).first;
}
}
@@ -306,7 +307,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
item.iconResId = R.drawable.ic_qs_bluetooth_connected;
int batteryLevel = device.getBatteryLevel();
if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- item.icon = new BluetoothBatteryTileIcon(batteryLevel,
+ item.icon = new BluetoothBatteryTileIcon(device,
1 /* iconScale */);
item.line2 = mContext.getString(
R.string.quick_settings_connected_battery_level,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index 9214eef61df5..5ae7f22c4905 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -31,7 +31,7 @@ oneway interface IRecentsNonSystemUserCallbacks {
void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecents(int recentsGrowTarget);
void onConfigurationChanged();
- void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+ void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode,
in Rect initialBounds);
void onDraggingInRecents(float distanceFromTop);
void onDraggingInRecentsEnded(float velocity);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index ce1438a14e52..2250e410c56d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -394,7 +394,7 @@ public class Recents extends SystemUI
}
@Override
- public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds,
+ public boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds,
int metricsDockAction) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
@@ -426,15 +426,16 @@ public class Recents extends SystemUI
runningTask.topActivity.flattenToShortString());
}
if (sSystemServicesProxy.isSystemUser(currentUser)) {
- mImpl.dockTopTask(runningTask.id, dragMode, stackCreateMode, initialBounds);
+ mImpl.splitPrimaryTask(runningTask.id, dragMode, stackCreateMode,
+ initialBounds);
} else {
if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
- callbacks.dockTopTask(runningTask.id, dragMode, stackCreateMode,
- initialBounds);
+ callbacks.splitPrimaryTask(runningTask.id, dragMode,
+ stackCreateMode, initialBounds);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 868ed64bab2e..1533e0a1fff2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -641,13 +641,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
showRelativeAffiliatedTask(false);
}
- public void dockTopTask(int topTaskId, int dragMode,
- int stackCreateMode, Rect initialBounds) {
+ public void splitPrimaryTask(int taskId, int dragMode, int stackCreateMode,
+ Rect initialBounds) {
SystemServicesProxy ssp = Recents.getSystemServices();
// Make sure we inform DividerView before we actually start the activity so we can change
// the resize mode already.
- if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {
+ if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) {
EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
showRecents(
false /* triggeredFromAltTab */,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
index ff9e89e9e00b..9493c78f6278 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -90,7 +90,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
}
@Override
- public void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+ public void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode,
Rect initialBounds) throws RemoteException {
SomeArgs args = SomeArgs.obtain();
args.argi1 = topTaskId;
@@ -144,7 +144,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
break;
case MSG_DOCK_TOP_TASK:
args = (SomeArgs) msg.obj;
- mImpl.dockTopTask(args.argi1, args.argi2, args.argi3 = 0,
+ mImpl.splitPrimaryTask(args.argi1, args.argi2, args.argi3 = 0,
(Rect) args.arg1);
break;
case MSG_ON_DRAGGING_IN_RECENTS:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 55ec5e7ed2ce..c4ac52b8b6d9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -291,7 +291,7 @@ public class SystemServicesProxy {
try {
final ActivityOptions options = ActivityOptions.makeBasic();
- options.setDockCreateMode(createMode);
+ options.setSplitScreenCreateMode(createMode);
options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
mIam.startActivityFromRecents(taskId, options.toBundle());
return true;
@@ -301,14 +301,15 @@ public class SystemServicesProxy {
return false;
}
- /** Docks an already resumed task to the side of the screen. */
- public boolean moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
+ /** Moves an already resumed task to the side of the screen to initiate split screen. */
+ public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
+ Rect initialBounds) {
if (mIam == null) {
return false;
}
try {
- return mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */,
+ return mIam.setTaskWindowingModeSplitScreenPrimary(taskId, createMode, true /* onTop */,
false /* animate */, initialBounds);
} catch (RemoteException e) {
e.printStackTrace();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
index 59f28680a6e0..65b96fbb52f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
@@ -16,8 +16,8 @@
package com.android.systemui.recents.views;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
@@ -71,19 +71,19 @@ public class DockState implements DropTarget {
public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
null, null, null);
public static final DockState LEFT = new DockState(DOCKED_LEFT,
- DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
new RectF(0, 0, 0.5f, 1));
public static final DockState TOP = new DockState(DOCKED_TOP,
- DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
new RectF(0, 0, 1, 0.5f));
public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
- DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
+ SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
new RectF(0.5f, 0, 1, 1));
public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
- DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
+ SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
new RectF(0, 0.5f, 1, 1));
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 195f4d3f480d..1cda30111db8 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -16,8 +16,8 @@
package com.android.systemui.shortcut;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.os.UserHandle.USER_CURRENT;
import android.app.ActivityManager;
@@ -92,8 +92,8 @@ public class ShortcutKeyDispatcher extends SystemUI
// If there is no window docked, we dock the top-most window.
Recents recents = getComponent(Recents.class);
int dockMode = (shortcutCode == SC_DOCK_LEFT)
- ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
- : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
List<ActivityManager.RecentTaskInfo> taskList =
ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT);
recents.showRecentApps(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
new file mode 100644
index 000000000000..5090f74d4019
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.WirelessUtils;
+import com.android.systemui.DemoMode;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import java.util.List;
+
+public class OperatorNameView extends TextView implements DemoMode, DarkReceiver,
+ SignalCallback, Tunable {
+
+ private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
+
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private boolean mDemoMode;
+
+ private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onRefreshCarrierInfo() {
+ updateText();
+ }
+ };
+
+ public OperatorNameView(Context context) {
+ this(context, null);
+ }
+
+ public OperatorNameView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public OperatorNameView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+ mKeyguardUpdateMonitor.registerCallback(mCallback);
+ Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
+ Dependency.get(NetworkController.class).addCallback(this);
+ Dependency.get(TunerService.class).addTunable(this, KEY_SHOW_OPERATOR_NAME);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mKeyguardUpdateMonitor.removeCallback(mCallback);
+ Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
+ Dependency.get(NetworkController.class).removeCallback(this);
+ Dependency.get(TunerService.class).removeTunable(this);
+ }
+
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+ }
+
+ @Override
+ public void setIsAirplaneMode(IconState icon) {
+ update();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ update();
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+ mDemoMode = true;
+ } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+ mDemoMode = false;
+ update();
+ } else if (mDemoMode && command.equals(COMMAND_OPERATOR)) {
+ setText(args.getString("name"));
+ }
+ }
+
+ private void update() {
+ boolean showOperatorName = Dependency.get(TunerService.class)
+ .getValue(KEY_SHOW_OPERATOR_NAME, 1) != 0;
+ setVisibility(showOperatorName ? VISIBLE : GONE);
+
+ boolean hasMobile = ConnectivityManager.from(mContext)
+ .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ boolean airplaneMode = WirelessUtils.isAirplaneModeOn(mContext);
+ if (!hasMobile || airplaneMode) {
+ setText(null);
+ setVisibility(GONE);
+ return;
+ }
+
+ if (!mDemoMode) {
+ updateText();
+ }
+ }
+
+ private void updateText() {
+ CharSequence displayText = null;
+ List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+ final int N = subs.size();
+ for (int i = 0; i < N; i++) {
+ int subId = subs.get(i).getSubscriptionId();
+ State simState = mKeyguardUpdateMonitor.getSimState(subId);
+ CharSequence carrierName = subs.get(i).getCarrierName();
+ if (!TextUtils.isEmpty(carrierName) && simState == State.READY) {
+ ServiceState ss = mKeyguardUpdateMonitor.getServiceState(subId);
+ if (ss != null && ss.getState() == ServiceState.STATE_IN_SERVICE) {
+ displayText = carrierName;
+ break;
+ }
+ }
+ }
+
+ setText(displayText);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 2c3f452e8274..61f3130b9be4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -60,6 +60,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private StatusBar mStatusBarComponent;
private DarkIconManager mDarkIconManager;
private SignalClusterView mSignalClusterView;
+ private View mOperatorNameFrame;
private SignalCallback mSignalCallback = new SignalCallback() {
@Override
@@ -97,6 +98,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
// Default to showing until we know otherwise.
showSystemIconArea(false);
initEmergencyCryptkeeperText();
+ initOperatorName();
}
@Override
@@ -150,8 +152,10 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {
if ((state1 & DISABLE_SYSTEM_INFO) != 0) {
hideSystemIconArea(animate);
+ hideOperatorName(animate);
} else {
showSystemIconArea(animate);
+ showOperatorName(animate);
}
}
if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {
@@ -207,6 +211,18 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
animateShow(mNotificationIconAreaInner, animate);
}
+ public void hideOperatorName(boolean animate) {
+ if (mOperatorNameFrame != null) {
+ animateHide(mOperatorNameFrame, animate);
+ }
+ }
+
+ public void showOperatorName(boolean animate) {
+ if (mOperatorNameFrame != null) {
+ animateShow(mOperatorNameFrame, animate);
+ }
+ }
+
/**
* Hides a view.
*/
@@ -268,4 +284,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
parent.removeView(emergencyViewStub);
}
}
+
+ private void initOperatorName() {
+ if (getResources().getBoolean(R.bool.config_showOperatorNameInStatusBar)) {
+ ViewStub stub = mStatusBar.findViewById(R.id.operator_name);
+ mOperatorNameFrame = stub.inflate();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index ee9a791585c4..8e0a506ac52d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -26,7 +26,6 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.Dependency;
@@ -206,7 +205,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
&& mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) {
Rect initialBounds = null;
int dragMode = calculateDragMode();
- int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ int createMode = ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
if (dragMode == DRAG_MODE_DIVIDER) {
initialBounds = new Rect();
mDivider.getView().calculateBoundsForPosition(mIsVertical
@@ -218,10 +217,10 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
initialBounds);
} else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX
< mContext.getResources().getDisplayMetrics().widthPixels / 2) {
- createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+ createMode = ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
}
- boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds,
- MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
+ boolean docked = mRecentsComponent.splitPrimaryTask(dragMode, createMode,
+ initialBounds, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
if (docked) {
mDragMode = dragMode;
if (mDragMode == DRAG_MODE_DIVIDER) {
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 b32abe686ada..fa2b8e89bfb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1538,8 +1538,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
int dockSide = WindowManagerProxy.getInstance().getDockSide();
if (dockSide == WindowManager.DOCKED_INVALID) {
- return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
+ return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
+ ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
} else {
Divider divider = getComponent(Divider.class);
if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
@@ -4128,6 +4128,9 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
}
+ if (modeChange || command.equals(COMMAND_OPERATOR)) {
+ dispatchDemoCommandToView(command, args, R.id.operator_name);
+ }
}
private void dispatchDemoCommandToView(String command, Bundle args, int id) {
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index f82d435dd360..2e0f394a53cc 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4750,6 +4750,10 @@ message MetricsEvent {
// OS: P
ANOMALY_TYPE_UNOPTIMIZED_BT = 1237;
+ // Open: Settings > Dev options > Oem unlock > lock it > warning dialog.
+ // OS: P
+ DIALOG_OEM_LOCK_INFO = 1238;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index ee0c04331da2..9d25055d6d5a 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -673,6 +673,10 @@ message StaEvent {
// Framework initiated disconnect. Sometimes generated to give an extra reason for a disconnect
// Should typically be followed by a NETWORK_DISCONNECTION_EVENT with a local_gen = true
TYPE_FRAMEWORK_DISCONNECT = 15;
+
+ // The NetworkAgent score for wifi has changed in a way that may impact
+ // connectivity
+ TYPE_SCORE_BREACH = 16;
}
enum FrameworkDisconnectReason {
@@ -784,6 +788,9 @@ message StaEvent {
// Authentication failure reason, as reported by WifiManager (calculated from state & deauth code)
optional AuthFailureReason auth_failure_reason = 13 [default = AUTH_FAILURE_UNKNOWN];
+
+ // NetworkAgent score of connected wifi
+ optional int32 last_score = 14 [default = -1];
}
// Wi-Fi Aware metrics
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 68546bd22221..ad308975e613 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -1163,8 +1163,10 @@ public final class BatteryService extends SystemService {
Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
private final IServiceNotification mNotification = new Notification();
+ // These variables are fixed after init.
private Callback mCallback;
private IHealthSupplier mHealthSupplier;
+ private String mInstanceName;
private final Object mLastServiceSetLock = new Object();
// Last IHealth service received.
@@ -1206,19 +1208,21 @@ public final class BatteryService extends SystemService {
IServiceManager manager = managerSupplier.get();
for (String name : sAllInstances) {
- if (manager.getTransport(IHealth.kInterfaceName, name) ==
+ if (manager.getTransport(IHealth.kInterfaceName, name) !=
IServiceManager.Transport.EMPTY) {
- continue;
+ mInstanceName = name;
+ break;
}
+ }
- manager.registerForNotifications(IHealth.kInterfaceName, name, mNotification);
- Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + name);
- return;
+ if (mInstanceName == null) {
+ throw new NoSuchElementException(String.format(
+ "No IHealth service instance among %s is available. Perhaps no permission?",
+ sAllInstances.toString()));
}
- throw new NoSuchElementException(String.format(
- "No IHealth service instance among %s is available. Perhaps no permission?",
- sAllInstances.toString()));
+ manager.registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+ Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
}
interface Callback {
@@ -1258,7 +1262,7 @@ public final class BatteryService extends SystemService {
public final void onRegistration(String interfaceName, String instanceName,
boolean preexisting) {
if (!IHealth.kInterfaceName.equals(interfaceName)) return;
- if (!sAllInstances.contains(instanceName)) return;
+ if (!mInstanceName.equals(instanceName)) return;
try {
// ensures the order of multiple onRegistration on different threads.
synchronized (mLastServiceSetLock) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e9f1a1f8e0b0..0a100672b684 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,7 +26,7 @@ import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REMOVE_TASKS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
@@ -10459,7 +10459,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
+ " to windowingMode=" + windowingMode + " toTop=" + toTop);
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
+ mWindowManager.setDockedStackCreateState(SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
null /* initialBounds */);
}
@@ -10506,7 +10506,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (stack.inSplitScreenPrimaryWindowingMode()) {
mWindowManager.setDockedStackCreateState(
- DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
}
task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
"moveTaskToStack");
@@ -10517,32 +10517,34 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
- * Moves the input task to the docked stack.
+ * Moves the input task to the primary-split-screen stack.
*
* @param taskId Id of task to move.
- * @param createMode The mode the docked stack should be created in if it doesn't exist
- * already. See
- * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT}
+ * @param createMode The mode the primary split screen stack should be created in if it doesn't
+ * exist already. See
+ * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
* and
- * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT}
+ * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
* @param toTop If the task and stack should be moved to the top.
* @param animate Whether we should play an animation for the moving the task
- * @param initialBounds If the docked stack gets created, it will use these bounds for the
- * docked stack. Pass {@code null} to use default bounds.
+ * @param initialBounds If the primary stack gets created, it will use these bounds for the
+ * stack. Pass {@code null} to use default bounds.
*/
@Override
- public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
- Rect initialBounds) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
+ public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+ boolean animate, Rect initialBounds) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "setTaskWindowingModeSplitScreenPrimary()");
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
if (task == null) {
- Slog.w(TAG, "moveTaskToDockedStack: No task for id=" + taskId);
+ Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
return false;
}
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
+ if (DEBUG_STACK) Slog.d(TAG_STACK,
+ "setTaskWindowingModeSplitScreenPrimary: moving task=" + taskId
+ " to createMode=" + createMode + " toTop=" + toTop);
mWindowManager.setDockedStackCreateState(createMode, initialBounds);
@@ -10555,7 +10557,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// TODO: Should just change windowing mode vs. re-parenting...
final boolean moved = task.reparent(stack, toTop,
REPARENT_KEEP_STACK_AT_FRONT, animate, !DEFER_RESUME,
- "moveTaskToDockedStack");
+ "setTaskWindowingModeSplitScreenPrimary");
if (moved) {
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
@@ -17076,22 +17078,39 @@ public class ActivityManagerService extends IActivityManager.Stub
return stringifySize(size * 1024, 1024);
}
- // Update this version number in case you change the 'compact' format
+ // Update this version number if you change the 'compact' format.
private static final int MEMINFO_COMPACT_VERSION = 1;
+ private static class MemoryUsageDumpOptions {
+ boolean dumpDetails;
+ boolean dumpFullDetails;
+ boolean dumpDalvik;
+ boolean dumpSummaryOnly;
+ boolean dumpUnreachable;
+ boolean oomOnly;
+ boolean isCompact;
+ boolean localOnly;
+ boolean packages;
+ boolean isCheckinRequest;
+ boolean dumpSwapPss;
+ boolean dumpProto;
+ }
+
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
- boolean dumpDetails = false;
- boolean dumpFullDetails = false;
- boolean dumpDalvik = false;
- boolean dumpSummaryOnly = false;
- boolean dumpUnreachable = false;
- boolean oomOnly = false;
- boolean isCompact = false;
- boolean localOnly = false;
- boolean packages = false;
- boolean isCheckinRequest = false;
- boolean dumpSwapPss = false;
+ MemoryUsageDumpOptions opts = new MemoryUsageDumpOptions();
+ opts.dumpDetails = false;
+ opts.dumpFullDetails = false;
+ opts.dumpDalvik = false;
+ opts.dumpSummaryOnly = false;
+ opts.dumpUnreachable = false;
+ opts.oomOnly = false;
+ opts.isCompact = false;
+ opts.localOnly = false;
+ opts.packages = false;
+ opts.isCheckinRequest = false;
+ opts.dumpSwapPss = false;
+ opts.dumpProto = false;
int opti = 0;
while (opti < args.length) {
@@ -17101,29 +17120,31 @@ public class ActivityManagerService extends IActivityManager.Stub
}
opti++;
if ("-a".equals(opt)) {
- dumpDetails = true;
- dumpFullDetails = true;
- dumpDalvik = true;
- dumpSwapPss = true;
+ opts.dumpDetails = true;
+ opts.dumpFullDetails = true;
+ opts.dumpDalvik = true;
+ opts.dumpSwapPss = true;
} else if ("-d".equals(opt)) {
- dumpDalvik = true;
+ opts.dumpDalvik = true;
} else if ("-c".equals(opt)) {
- isCompact = true;
+ opts.isCompact = true;
} else if ("-s".equals(opt)) {
- dumpDetails = true;
- dumpSummaryOnly = true;
+ opts.dumpDetails = true;
+ opts.dumpSummaryOnly = true;
} else if ("-S".equals(opt)) {
- dumpSwapPss = true;
+ opts.dumpSwapPss = true;
} else if ("--unreachable".equals(opt)) {
- dumpUnreachable = true;
+ opts.dumpUnreachable = true;
} else if ("--oom".equals(opt)) {
- oomOnly = true;
+ opts.oomOnly = true;
} else if ("--local".equals(opt)) {
- localOnly = true;
+ opts.localOnly = true;
} else if ("--package".equals(opt)) {
- packages = true;
+ opts.packages = true;
} else if ("--checkin".equals(opt)) {
- isCheckinRequest = true;
+ opts.isCheckinRequest = true;
+ } else if ("--proto".equals(opt)) {
+ opts.dumpProto = true;
} else if ("-h".equals(opt)) {
pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]");
@@ -17137,6 +17158,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" --package: interpret process arg as package, dumping all");
pw.println(" processes that have loaded that package.");
pw.println(" --checkin: dump data for a checkin");
+ pw.println(" --proto: dump data to proto");
pw.println("If [process] is specified it can be the name or ");
pw.println("pid of a specific process to dump.");
return;
@@ -17145,21 +17167,33 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ String[] innerArgs = new String[args.length-opti];
+ System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
+
+ ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, opts.packages, args);
+ if (opts.dumpProto) {
+ dumpApplicationMemoryUsage(fd, pw, opts, innerArgs, brief, procs);
+ } else {
+ dumpApplicationMemoryUsage(fd, pw, prefix, opts, innerArgs, brief, procs, categoryPw);
+ }
+ }
+
+ final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
+ MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief,
+ ArrayList<ProcessRecord> procs, PrintWriter categoryPw) {
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
final long[] tmpLong = new long[1];
- ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, packages, args);
if (procs == null) {
// No Java processes. Maybe they want to print a native process.
- if (args != null && args.length > opti
- && args[opti].charAt(0) != '-') {
+ if (innerArgs.length > 0 && innerArgs[0].charAt(0) != '-') {
ArrayList<ProcessCpuTracker.Stats> nativeProcs
= new ArrayList<ProcessCpuTracker.Stats>();
updateCpuStatsNow();
int findPid = -1;
try {
- findPid = Integer.parseInt(args[opti]);
+ findPid = Integer.parseInt(innerArgs[0]);
} catch (NumberFormatException e) {
}
synchronized (mProcessCpuTracker) {
@@ -17167,51 +17201,48 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i=0; i<N; i++) {
ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
if (st.pid == findPid || (st.baseName != null
- && st.baseName.equals(args[opti]))) {
+ && st.baseName.equals(innerArgs[0]))) {
nativeProcs.add(st);
}
}
}
if (nativeProcs.size() > 0) {
- dumpApplicationMemoryUsageHeader(pw, uptime, realtime, isCheckinRequest,
- isCompact);
+ dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest,
+ opts.isCompact);
Debug.MemoryInfo mi = null;
for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
final ProcessCpuTracker.Stats r = nativeProcs.get(i);
final int pid = r.pid;
- if (!isCheckinRequest && dumpDetails) {
+ if (!opts.isCheckinRequest && opts.dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **");
}
if (mi == null) {
mi = new Debug.MemoryInfo();
}
- if (dumpDetails || (!brief && !oomOnly)) {
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
Debug.getMemoryInfo(pid, mi);
} else {
mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
mi.dalvikPrivateDirty = (int)tmpLong[0];
}
- ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, pid, r.baseName, 0, 0, 0, 0, 0, 0);
- if (isCheckinRequest) {
+ ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest, opts.dumpFullDetails,
+ opts.dumpDalvik, opts.dumpSummaryOnly, pid, r.baseName, 0, 0, 0, 0, 0, 0);
+ if (opts.isCheckinRequest) {
pw.println();
}
}
return;
}
}
- pw.println("No process found for: " + args[opti]);
+ pw.println("No process found for: " + innerArgs[0]);
return;
}
- if (!brief && !oomOnly && (procs.size() == 1 || isCheckinRequest || packages)) {
- dumpDetails = true;
+ if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) {
+ opts.dumpDetails = true;
}
- dumpApplicationMemoryUsageHeader(pw, uptime, realtime, isCheckinRequest, isCompact);
-
- String[] innerArgs = new String[args.length-opti];
- System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
+ dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest, opts.isCompact);
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
@@ -17219,9 +17250,9 @@ public class ActivityManagerService extends IActivityManager.Stub
long nativeSwapPss = 0;
long dalvikPss = 0;
long dalvikSwapPss = 0;
- long[] dalvikSubitemPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ long[] dalvikSubitemPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
- long[] dalvikSubitemSwapPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ long[] dalvikSubitemSwapPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
long otherPss = 0;
long otherSwapPss = 0;
@@ -17253,24 +17284,24 @@ public class ActivityManagerService extends IActivityManager.Stub
hasActivities = r.activities.size() > 0;
}
if (thread != null) {
- if (!isCheckinRequest && dumpDetails) {
+ if (!opts.isCheckinRequest && opts.dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
}
if (mi == null) {
mi = new Debug.MemoryInfo();
}
- if (dumpDetails || (!brief && !oomOnly)) {
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
Debug.getMemoryInfo(pid, mi);
hasSwapPss = mi.hasSwappedOutPss;
} else {
mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
mi.dalvikPrivateDirty = (int)tmpLong[0];
}
- if (dumpDetails) {
- if (localOnly) {
- ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0);
- if (isCheckinRequest) {
+ if (opts.dumpDetails) {
+ if (opts.localOnly) {
+ ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest, opts.dumpFullDetails,
+ opts.dumpDalvik, opts.dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0);
+ if (opts.isCheckinRequest) {
pw.println();
}
} else {
@@ -17279,19 +17310,19 @@ public class ActivityManagerService extends IActivityManager.Stub
TransferPipe tp = new TransferPipe();
try {
thread.dumpMemInfo(tp.getWriteFd(),
- mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs);
+ mi, opts.isCheckinRequest, opts.dumpFullDetails,
+ opts.dumpDalvik, opts.dumpSummaryOnly, opts.dumpUnreachable, innerArgs);
tp.go(fd);
} finally {
tp.kill();
}
} catch (IOException e) {
- if (!isCheckinRequest) {
+ if (!opts.isCheckinRequest) {
pw.println("Got IoException! " + e);
pw.flush();
}
} catch (RemoteException e) {
- if (!isCheckinRequest) {
+ if (!opts.isCheckinRequest) {
pw.println("Got RemoteException! " + e);
pw.flush();
}
@@ -17310,7 +17341,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (!isCheckinRequest && mi != null) {
+ if (!opts.isCheckinRequest && mi != null) {
totalPss += myTotalPss;
totalSwapPss += myTotalSwapPss;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
@@ -17363,7 +17394,7 @@ public class ActivityManagerService extends IActivityManager.Stub
long nativeProcTotalPss = 0;
- if (!isCheckinRequest && procs.size() > 1 && !packages) {
+ if (!opts.isCheckinRequest && procs.size() > 1 && !opts.packages) {
// If we are showing aggregations, also look for native processes to
// include so that our aggregations are more accurate.
updateCpuStatsNow();
@@ -17376,7 +17407,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (mi == null) {
mi = new Debug.MemoryInfo();
}
- if (!brief && !oomOnly) {
+ if (!brief && !opts.oomOnly) {
Debug.getMemoryInfo(st.pid, mi);
} else {
mi.nativePss = (int)Debug.getPss(st.pid, tmpLong, null);
@@ -17463,7 +17494,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
for (int j=0; j<oomPss.length; j++) {
if (oomPss[j] != 0) {
- String label = isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
+ String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
: DUMP_MEM_OOM_LABEL[j];
MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j],
DUMP_MEM_OOM_ADJ[j]);
@@ -17472,26 +17503,26 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- dumpSwapPss = dumpSwapPss && hasSwapPss && totalSwapPss != 0;
- if (!brief && !oomOnly && !isCompact) {
+ opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && totalSwapPss != 0;
+ if (!brief && !opts.oomOnly && !opts.isCompact) {
pw.println();
pw.println("Total PSS by process:");
- dumpMemItems(pw, " ", "proc", procMems, true, isCompact, dumpSwapPss);
+ dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, opts.dumpSwapPss);
pw.println();
}
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.println("Total PSS by OOM adjustment:");
}
- dumpMemItems(pw, " ", "oom", oomMems, false, isCompact, dumpSwapPss);
- if (!brief && !oomOnly) {
+ dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, opts.dumpSwapPss);
+ if (!brief && !opts.oomOnly) {
PrintWriter out = categoryPw != null ? categoryPw : pw;
- if (!isCompact) {
+ if (!opts.isCompact) {
out.println();
out.println("Total PSS by category:");
}
- dumpMemItems(out, " ", "cat", catMems, true, isCompact, dumpSwapPss);
+ dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, opts.dumpSwapPss);
}
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.println();
}
MemInfoReader memInfo = new MemInfoReader();
@@ -17509,7 +17540,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
if (!brief) {
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.print("Total RAM: "); pw.print(stringifyKBSize(memInfo.getTotalSizeKb()));
pw.print(" (status ");
switch (mLastMemoryLevel) {
@@ -17550,7 +17581,7 @@ public class ActivityManagerService extends IActivityManager.Stub
long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss
+ memInfo.getKernelUsedSizeKb())); pw.print(" (");
pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + ");
@@ -17561,7 +17592,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (!brief) {
if (memInfo.getZramTotalSizeKb() != 0) {
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.print(" ZRAM: ");
pw.print(stringifyKBSize(memInfo.getZramTotalSizeKb()));
pw.print(" physical used for ");
@@ -17577,7 +17608,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
final long[] ksm = getKsmInfo();
- if (!isCompact) {
+ if (!opts.isCompact) {
if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
|| ksm[KSM_VOLATILE] != 0) {
pw.print(" KSM: "); pw.print(stringifyKBSize(ksm[KSM_SHARING]));
@@ -17626,6 +17657,17 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw,
+ MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief,
+ ArrayList<ProcessRecord> procs) {
+ ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ // TODO: implement
+ pw.println("Not yet implemented. Have a cookie instead! :]");
+
+ proto.flush();
+ }
+
private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
long memtrack, String name) {
sb.append(" ");
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6ec158efa1cd..3506d6b1602b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4465,7 +4465,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
try {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
mWindowManager.setDockedStackCreateState(
- activityOptions.getDockCreateMode(), null /* initialBounds */);
+ activityOptions.getSplitScreenCreateMode(), null /* initialBounds */);
// Defer updating the stack in which recents is until the app transition is done, to
// not run into issues where we still need to draw the task in recents but the
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 061fd8da9d60..6b77d8326a39 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -2,7 +2,7 @@ set noparent
ek@google.com
hugobenichi@google.com
-jsharkey@google.com
+jsharkey@android.com
lorenzo@google.com
satk@google.com
silberst@google.com
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index a3c6167075d9..860ff387d668 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -24,7 +24,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.content.ClipData;
import android.graphics.PixelFormat;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.util.Slog;
import android.view.Display;
@@ -33,7 +35,6 @@ import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
-import com.android.server.wm.WindowManagerService.H;
/**
* Managing drag and drop operations initiated by View#startDragAndDrop.
@@ -41,13 +42,28 @@ import com.android.server.wm.WindowManagerService.H;
class DragDropController {
private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f;
private static final long DRAG_TIMEOUT_MS = 5000;
+
+ // Messages for Handler.
+ private static final int MSG_DRAG_START_TIMEOUT = 0;
+ static final int MSG_DRAG_END_TIMEOUT = 1;
+ static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 2;
+ static final int MSG_ANIMATION_END = 3;
+
DragState mDragState;
+ private WindowManagerService mService;
+ private final Handler mHandler;
+
boolean dragDropActiveLocked() {
return mDragState != null;
}
- IBinder prepareDrag(WindowManagerService service, SurfaceSession session, int callerPid,
+ DragDropController(WindowManagerService service, Looper looper) {
+ mService = service;
+ mHandler = new DragHandler(service, looper);
+ }
+
+ IBinder prepareDrag(SurfaceSession session, int callerPid,
int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "prepare drag surface: w=" + width + " h=" + height
@@ -57,7 +73,7 @@ class DragDropController {
IBinder token = null;
- synchronized (service.mWindowMap) {
+ synchronized (mService.mWindowMap) {
if (dragDropActiveLocked()) {
Slog.w(TAG_WM, "Drag already in progress");
return null;
@@ -65,7 +81,7 @@ class DragDropController {
// TODO(multi-display): support other displays
final DisplayContent displayContent =
- service.getDefaultDisplayContentLocked();
+ mService.getDefaultDisplayContentLocked();
final Display display = displayContent.getDisplay();
final SurfaceControl surface = new SurfaceControl.Builder(session)
@@ -84,29 +100,27 @@ class DragDropController {
outSurface.copyFrom(surface);
final IBinder winBinder = window.asBinder();
token = new Binder();
- mDragState = new DragState(service, token, surface, flags, winBinder);
+ mDragState = new DragState(mService, token, surface, flags, winBinder);
mDragState.mPid = callerPid;
mDragState.mUid = callerUid;
mDragState.mOriginalAlpha = alpha;
token = mDragState.mToken = new Binder();
// 5 second timeout for this window to actually begin the drag
- service.mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
- Message msg = service.mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
- service.mH.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
+ sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
}
return token;
}
- boolean performDrag(WindowManagerService service, IWindow window, IBinder dragToken,
+ boolean performDrag(IWindow window, IBinder dragToken,
int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
ClipData data) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
}
- synchronized (service.mWindowMap) {
+ synchronized (mService.mWindowMap) {
if (mDragState == null) {
Slog.w(TAG_WM, "No drag prepared");
throw new IllegalStateException("performDrag() without prepareDrag()");
@@ -117,7 +131,7 @@ class DragDropController {
throw new IllegalStateException("performDrag() does not match prepareDrag()");
}
- final WindowState callingWin = service.windowForClientLocked(null, window, false);
+ final WindowState callingWin = mService.windowForClientLocked(null, window, false);
if (callingWin == null) {
Slog.w(TAG_WM, "Bad requesting window " + window);
return false; // !!! TODO: throw here?
@@ -127,12 +141,12 @@ class DragDropController {
// the drag initiation (e.g. an alarm window popped up just as the application
// called performDrag()
- service.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder());
+ mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());
// !!! TODO: extract the current touch (x, y) in screen coordinates. That
// will let us eliminate the (touchX,touchY) parameters from the API.
- // !!! FIXME: put all this heavy stuff onto the mH looper, as well as
+ // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
// the actual drag event dispatch stuff in the dragstate
final DisplayContent displayContent = callingWin.getDisplayContent();
@@ -141,7 +155,7 @@ class DragDropController {
}
Display display = displayContent.getDisplay();
mDragState.register(display);
- if (!service.mInputManager.transferTouchFocus(callingWin.mInputChannel,
+ if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
mDragState.getInputChannel())) {
Slog.e(TAG_WM, "Unable to transfer touch focus");
mDragState.unregister();
@@ -152,8 +166,8 @@ class DragDropController {
mDragState.mDisplayContent = displayContent;
mDragState.mData = data;
- mDragState.broadcastDragStartedLw(touchX, touchY);
- mDragState.overridePointerIconLw(touchSource);
+ mDragState.broadcastDragStartedLocked(touchX, touchY);
+ mDragState.overridePointerIconLocked(touchSource);
// remember the thumb offsets for later
mDragState.mThumbOffsetX = thumbCenterX;
@@ -163,32 +177,32 @@ class DragDropController {
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
TAG_WM, ">>> OPEN TRANSACTION performDrag");
- service.openSurfaceTransaction();
+ mService.openSurfaceTransaction();
try {
surfaceControl.setPosition(touchX - thumbCenterX,
touchY - thumbCenterY);
- surfaceControl.setLayer(mDragState.getDragLayerLw());
+ surfaceControl.setLayer(mDragState.getDragLayerLocked());
surfaceControl.setLayerStack(display.getLayerStack());
surfaceControl.show();
} finally {
- service.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction();
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
TAG_WM, "<<< CLOSE TRANSACTION performDrag");
}
- mDragState.notifyLocationLw(touchX, touchY);
+ mDragState.notifyLocationLocked(touchX, touchY);
}
return true; // success!
}
- void reportDropResult(WindowManagerService service, IWindow window, boolean consumed) {
+ void reportDropResult(IWindow window, boolean consumed) {
IBinder token = window.asBinder();
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
}
- synchronized (service.mWindowMap) {
+ synchronized (mService.mWindowMap) {
if (mDragState == null) {
// Most likely the drop recipient ANRed and we ended the drag
// out from under it. Log the issue and move on.
@@ -205,24 +219,24 @@ class DragDropController {
// The right window has responded, even if it's no longer around,
// so be sure to halt the timeout even if the later WindowState
// lookup fails.
- service.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder());
- WindowState callingWin = service.windowForClientLocked(null, window, false);
+ mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
+ WindowState callingWin = mService.windowForClientLocked(null, window, false);
if (callingWin == null) {
Slog.w(TAG_WM, "Bad result-reporting window " + window);
return; // !!! TODO: throw here?
}
mDragState.mDragResult = consumed;
- mDragState.endDragLw();
+ mDragState.endDragLocked();
}
}
- void cancelDragAndDrop(WindowManagerService service, IBinder dragToken) {
+ void cancelDragAndDrop(IBinder dragToken) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "cancelDragAndDrop");
}
- synchronized (service.mWindowMap) {
+ synchronized (mService.mWindowMap) {
if (mDragState == null) {
Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
@@ -236,7 +250,7 @@ class DragDropController {
}
mDragState.mDragResult = false;
- mDragState.cancelDragLw();
+ mDragState.cancelDragLocked();
}
}
@@ -252,49 +266,90 @@ class DragDropController {
}
}
- void handleMessage(WindowManagerService service, Message msg) {
- switch (msg.what) {
- case H.DRAG_START_TIMEOUT: {
- IBinder win = (IBinder) msg.obj;
- if (DEBUG_DRAG) {
- Slog.w(TAG_WM, "Timeout starting drag by win " + win);
- }
- synchronized (service.mWindowMap) {
- // !!! TODO: ANR the app that has failed to start the drag in time
- if (mDragState != null) {
- mDragState.unregister();
- mDragState.reset();
- mDragState = null;
+ /**
+ * Sends a message to the Handler managed by DragDropController.
+ */
+ void sendHandlerMessage(int what, Object arg) {
+ mHandler.obtainMessage(what, arg).sendToTarget();
+ }
+
+ /**
+ * Sends a timeout message to the Handler managed by DragDropController.
+ */
+ void sendTimeoutMessage(int what, Object arg) {
+ mHandler.removeMessages(what, arg);
+ final Message msg = mHandler.obtainMessage(what, arg);
+ mHandler.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
+ }
+
+ private class DragHandler extends Handler {
+ /**
+ * Lock for window manager.
+ */
+ private final WindowManagerService mService;
+
+ DragHandler(WindowManagerService service, Looper looper) {
+ super(looper);
+ mService = service;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_DRAG_START_TIMEOUT: {
+ IBinder win = (IBinder) msg.obj;
+ if (DEBUG_DRAG) {
+ Slog.w(TAG_WM, "Timeout starting drag by win " + win);
}
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the app that has failed to start the drag in time
+ if (mDragState != null) {
+ mDragState.unregister();
+ mDragState.reset();
+ mDragState = null;
+ }
+ }
+ break;
}
- break;
- }
- case H.DRAG_END_TIMEOUT: {
- IBinder win = (IBinder) msg.obj;
- if (DEBUG_DRAG) {
- Slog.w(TAG_WM, "Timeout ending drag to win " + win);
+ case MSG_DRAG_END_TIMEOUT: {
+ IBinder win = (IBinder) msg.obj;
+ if (DEBUG_DRAG) {
+ Slog.w(TAG_WM, "Timeout ending drag to win " + win);
+ }
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the drag-receiving app
+ if (mDragState != null) {
+ mDragState.mDragResult = false;
+ mDragState.endDragLocked();
+ }
+ }
+ break;
}
- synchronized (service.mWindowMap) {
- // !!! TODO: ANR the drag-receiving app
- if (mDragState != null) {
- mDragState.mDragResult = false;
- mDragState.endDragLw();
+
+ case MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT: {
+ if (DEBUG_DRAG)
+ Slog.d(TAG_WM, "Drag ending; tearing down input channel");
+ DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
+ if (interceptor != null) {
+ synchronized (mService.mWindowMap) {
+ interceptor.tearDown();
+ }
}
+ break;
}
- break;
- }
- case H.TEAR_DOWN_DRAG_AND_DROP_INPUT: {
- if (DEBUG_DRAG)
- Slog.d(TAG_WM, "Drag ending; tearing down input channel");
- DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
- if (interceptor != null) {
- synchronized (service.mWindowMap) {
- interceptor.tearDown();
+ case MSG_ANIMATION_END: {
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
+ "plyaing animation");
+ return;
+ }
+ mDragState.onAnimationEndLocked();
}
+ break;
}
- break;
}
}
}
diff --git a/services/core/java/com/android/server/wm/DragInputEventReceiver.java b/services/core/java/com/android/server/wm/DragInputEventReceiver.java
new file mode 100644
index 000000000000..b4bbc9055631
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DragInputEventReceiver.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.InputDevice.SOURCE_CLASS_POINTER;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.MotionEvent.BUTTON_STYLUS_PRIMARY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.os.Looper;
+import android.util.Slog;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+
+/**
+ * Input receiver for drag and drop
+ */
+class DragInputEventReceiver extends InputEventReceiver {
+ private final WindowManagerService mService;
+ private final DragDropController mDragDropController;
+
+ // Set, if stylus button was down at the start of the drag.
+ private boolean mStylusButtonDownAtStart;
+ // Indicates the first event to check for button state.
+ private boolean mIsStartEvent = true;
+ // Set to true to ignore input events after the drag gesture is complete but the drag events
+ // are still being dispatched.
+ private boolean mMuteInput = false;
+
+ public DragInputEventReceiver(InputChannel inputChannel, Looper looper,
+ DragDropController controller, WindowManagerService service) {
+ super(inputChannel, looper);
+ mDragDropController = controller;
+ mService = service;
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event, int displayId) {
+ boolean handled = false;
+ try {
+ synchronized (mService.mWindowMap) {
+ if (!mDragDropController.dragDropActiveLocked()) {
+ // The drag has ended but the clean-up message has not been processed by
+ // window manager. Drop events that occur after this until window manager
+ // has a chance to clean-up the input handle.
+ handled = true;
+ return;
+ }
+ if (!(event instanceof MotionEvent)
+ || (event.getSource() & SOURCE_CLASS_POINTER) == 0
+ || mMuteInput) {
+ return;
+ }
+ final MotionEvent motionEvent = (MotionEvent) event;
+ boolean endDrag = false;
+ final float newX = motionEvent.getRawX();
+ final float newY = motionEvent.getRawY();
+ final boolean isStylusButtonDown =
+ (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0;
+
+ if (mIsStartEvent) {
+ if (isStylusButtonDown) {
+ // First event and the button was down, check for the button being
+ // lifted in the future, if that happens we'll drop the item.
+ mStylusButtonDownAtStart = true;
+ }
+ mIsStartEvent = false;
+ }
+
+ switch (motionEvent.getAction()) {
+ case ACTION_DOWN: {
+ if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
+ }
+ break;
+
+ case ACTION_MOVE: {
+ if (mStylusButtonDownAtStart && !isStylusButtonDown) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "Button no longer pressed; dropping at "
+ + newX + "," + newY);
+ }
+ mMuteInput = true;
+ endDrag = mDragDropController.mDragState
+ .notifyDropLocked(newX, newY);
+ } else {
+ // move the surface and tell the involved window(s) where we are
+ mDragDropController.mDragState.notifyMoveLocked(newX, newY);
+ }
+ }
+ break;
+
+ case ACTION_UP: {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "Got UP on move channel; dropping at "
+ + newX + "," + newY);
+ }
+ mMuteInput = true;
+ endDrag = mDragDropController.mDragState
+ .notifyDropLocked(newX, newY);
+ }
+ break;
+
+ case ACTION_CANCEL: {
+ if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
+ mMuteInput = true;
+ endDrag = true;
+ }
+ break;
+ }
+
+ if (endDrag) {
+ if (DEBUG_DRAG)
+ Slog.d(TAG_WM, "Drag ended; tearing down state");
+ // tell all the windows that the drag has ended
+ // endDragLocked will post back to looper to dispose the receiver
+ // since we still need the receiver for the last finishInputEvent.
+ mDragDropController.mDragState.endDragLocked();
+ mStylusButtonDownAtStart = false;
+ mIsStartEvent = true;
+ }
+
+ handled = true;
+ }
+ } catch (Exception e) {
+ Slog.e(TAG_WM, "Exception caught by drag handleMotion", e);
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 11f22411d4c5..9a955de9706c 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
+import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
+import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -29,14 +32,10 @@ import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
-import android.graphics.Matrix;
import android.graphics.Point;
import android.hardware.input.InputManager;
import android.os.Build;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -50,19 +49,14 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.PointerIcon;
import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.view.animation.Transformation;
+import com.android.internal.view.IDragAndDropPermissions;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
-import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
-import com.android.server.wm.WindowManagerService.H;
-
-import com.android.internal.view.IDragAndDropPermissions;
import java.util.ArrayList;
@@ -86,10 +80,8 @@ class DragState {
private static final String ANIMATED_PROPERTY_ALPHA = "alpha";
private static final String ANIMATED_PROPERTY_SCALE = "scale";
- // Messages for Handler.
- private static final int MSG_ANIMATION_END = 0;
-
final WindowManagerService mService;
+ final DragDropController mDragDropController;
IBinder mToken;
/**
* Do not use the variable from the out of animation thread while mAnimator is not null.
@@ -118,17 +110,16 @@ class DragState {
@Nullable private ValueAnimator mAnimator;
private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
private Point mDisplaySize = new Point();
- private final Handler mHandler;
DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
int flags, IBinder localWin) {
mService = service;
+ mDragDropController = service.mDragDropController;
mToken = token;
mSurfaceControl = surface;
mFlags = flags;
mLocalWin = localWin;
mNotifiedWindows = new ArrayList<WindowState>();
- mHandler = new DragStateHandler(service.mH.getLooper());
}
void reset() {
@@ -159,8 +150,8 @@ class DragState {
mServerChannel = channels[0];
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
- mInputEventReceiver = mService.new DragInputEventReceiver(mClientChannel,
- mService.mH.getLooper());
+ mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
+ mService.mH.getLooper(), mDragDropController, mService);
mDragApplicationHandle = new InputApplicationHandle(null);
mDragApplicationHandle.name = "drag";
@@ -171,7 +162,7 @@ class DragState {
display.getDisplayId());
mDragWindowHandle.name = "drag";
mDragWindowHandle.inputChannel = mServerChannel;
- mDragWindowHandle.layer = getDragLayerLw();
+ mDragWindowHandle.layer = getDragLayerLocked();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutNanos =
@@ -250,14 +241,14 @@ class DragState {
Slog.e(TAG_WM, "Unregister of nonexistent drag input channel");
} else {
// Input channel should be disposed on the thread where the input is being handled.
- mService.mH.obtainMessage(
- H.TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor).sendToTarget();
+ mDragDropController.sendHandlerMessage(
+ MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
mInputInterceptor = null;
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
}
}
- int getDragLayerLw() {
+ int getDragLayerLocked() {
return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
@@ -265,7 +256,7 @@ class DragState {
/* call out to each visible window/session informing it about the drag
*/
- void broadcastDragStartedLw(final float touchX, final float touchY) {
+ void broadcastDragStartedLocked(final float touchX, final float touchY) {
mOriginalX = mCurrentX = touchX;
mOriginalY = mCurrentY = touchY;
@@ -292,7 +283,7 @@ class DragState {
}
mDisplayContent.forAllWindows(w -> {
- sendDragStartedLw(w, touchX, touchY, mDataDescription);
+ sendDragStartedLocked(w, touchX, touchY, mDataDescription);
}, false /* traverseTopToBottom */ );
}
@@ -304,7 +295,7 @@ class DragState {
* This method clones the 'event' parameter if it's being delivered to the same
* process, so it's safe for the caller to call recycle() on the event afterwards.
*/
- private void sendDragStartedLw(WindowState newWin, float touchX, float touchY,
+ private void sendDragStartedLocked(WindowState newWin, float touchX, float touchY,
ClipDescription desc) {
if (mDragInProgress && isValidDropTarget(newWin)) {
DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
@@ -353,7 +344,7 @@ class DragState {
* previously been notified, i.e. it became visible after the drag operation
* was begun. This is a rare case.
*/
- void sendDragStartedIfNeededLw(WindowState newWin) {
+ void sendDragStartedIfNeededLocked(WindowState newWin) {
if (mDragInProgress) {
// If we have sent the drag-started, we needn't do so again
if (isWindowNotified(newWin)) {
@@ -362,7 +353,7 @@ class DragState {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
}
- sendDragStartedLw(newWin, mCurrentX, mCurrentY, mDataDescription);
+ sendDragStartedLocked(newWin, mCurrentX, mCurrentY, mDataDescription);
}
}
@@ -375,7 +366,7 @@ class DragState {
return false;
}
- private void broadcastDragEndedLw() {
+ private void broadcastDragEndedLocked() {
final int myPid = Process.myPid();
if (DEBUG_DRAG) {
@@ -406,7 +397,7 @@ class DragState {
mDragInProgress = false;
}
- void endDragLw() {
+ void endDragLocked() {
if (mAnimator != null) {
return;
}
@@ -414,10 +405,10 @@ class DragState {
mAnimator = createReturnAnimationLocked();
return; // Will call cleanUpDragLw when the animation is done.
}
- cleanUpDragLw();
+ cleanUpDragLocked();
}
- void cancelDragLw() {
+ void cancelDragLocked() {
if (mAnimator != null) {
return;
}
@@ -430,14 +421,14 @@ class DragState {
// WindowManagerService, which will cause DragState#reset() while playing the
// cancel animation.
reset();
- mService.mDragDropController.mDragState = null;
+ mDragDropController.mDragState = null;
return;
}
mAnimator = createCancelAnimationLocked();
}
- private void cleanUpDragLw() {
- broadcastDragEndedLw();
+ private void cleanUpDragLocked() {
+ broadcastDragEndedLocked();
if (isFromSource(InputDevice.SOURCE_MOUSE)) {
mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
}
@@ -447,10 +438,10 @@ class DragState {
// free our resources and drop all the object references
reset();
- mService.mDragDropController.mDragState = null;
+ mDragDropController.mDragState = null;
}
- void notifyMoveLw(float x, float y) {
+ void notifyMoveLocked(float x, float y) {
if (mAnimator != null) {
return;
}
@@ -459,7 +450,7 @@ class DragState {
// Move the surface to the given touch
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
- TAG_WM, ">>> OPEN TRANSACTION notifyMoveLw");
+ TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
mService.openSurfaceTransaction();
try {
mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
@@ -469,12 +460,12 @@ class DragState {
} finally {
mService.closeSurfaceTransaction();
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
- TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLw");
+ TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLocked");
}
- notifyLocationLw(x, y);
+ notifyLocationLocked(x, y);
}
- void notifyLocationLw(float x, float y) {
+ void notifyLocationLocked(float x, float y) {
// Tell the affected window
WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
if (touchedWin != null && !isWindowNotified(touchedWin)) {
@@ -519,7 +510,7 @@ class DragState {
// Find the drop target and tell it about the data. Returns 'true' if we can immediately
// dispatch the global drag-ended message, 'false' if we need to wait for a
// result from the recipient.
- boolean notifyDropLw(float x, float y) {
+ boolean notifyDropLocked(float x, float y) {
if (mAnimator != null) {
return false;
}
@@ -563,9 +554,7 @@ class DragState {
touchedWin.mClient.dispatchDragEvent(evt);
// 5 second timeout for this window to respond to the drop
- mService.mH.removeMessages(H.DRAG_END_TIMEOUT, token);
- Message msg = mService.mH.obtainMessage(H.DRAG_END_TIMEOUT, token);
- mService.mH.sendMessageDelayed(msg, 5000);
+ mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
} catch (RemoteException e) {
Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
return true;
@@ -578,6 +567,15 @@ class DragState {
return false;
}
+ void onAnimationEndLocked() {
+ if (mAnimator == null) {
+ Slog.wtf(TAG_WM, "Unexpected null mAnimator");
+ return;
+ }
+ mAnimator = null;
+ cleanUpDragLocked();
+ }
+
private static DragEvent obtainDragEvent(WindowState win, int action,
float x, float y, Object localState,
ClipDescription description, ClipData data,
@@ -641,40 +639,13 @@ class DragState {
return (mTouchSource & source) == source;
}
- void overridePointerIconLw(int touchSource) {
+ void overridePointerIconLocked(int touchSource) {
mTouchSource = touchSource;
if (isFromSource(InputDevice.SOURCE_MOUSE)) {
InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
}
}
- private class DragStateHandler extends Handler {
- DragStateHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ANIMATION_END:
- synchronized (mService.mWindowMap) {
- if (mService.mDragDropController.mDragState != DragState.this) {
- Slog.wtf(TAG_WM, "mDragState is updated unexpectedly while " +
- "playing animation");
- return;
- }
- if (mAnimator == null) {
- Slog.wtf(TAG_WM, "Unexpected null mAnimator");
- return;
- }
- mAnimator = null;
- cleanUpDragLw();
- }
- break;
- }
- }
- }
-
private class AnimationListener
implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
@Override
@@ -708,7 +679,7 @@ class DragState {
public void onAnimationEnd(Animator animator) {
// Updating mDragState requires the WM lock so continues it on the out of
// AnimationThread.
- mHandler.sendEmptyMessage(MSG_ANIMATION_END);
+ mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
}
}
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 36753b7d5e04..d40db8cb5443 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,21 +16,36 @@
package com.android.server.wm;
+import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.view.Display;
import android.view.InputChannel;
import android.view.WindowManager;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
-class InputConsumerImpl {
+import java.io.PrintWriter;
+
+class InputConsumerImpl implements IBinder.DeathRecipient {
final WindowManagerService mService;
final InputChannel mServerChannel, mClientChannel;
final InputApplicationHandle mApplicationHandle;
final InputWindowHandle mWindowHandle;
- InputConsumerImpl(WindowManagerService service, String name, InputChannel inputChannel) {
+ final IBinder mToken;
+ final String mName;
+ final int mClientPid;
+ final UserHandle mClientUser;
+
+ InputConsumerImpl(WindowManagerService service, IBinder token, String name,
+ InputChannel inputChannel, int clientPid, UserHandle clientUser) {
mService = service;
+ mToken = token;
+ mName = name;
+ mClientPid = clientPid;
+ mClientUser = clientUser;
InputChannel[] channels = InputChannel.openInputChannelPair(name);
mServerChannel = channels[0];
@@ -68,6 +83,26 @@ class InputConsumerImpl {
mWindowHandle.scaleFactor = 1.0f;
}
+ void linkToDeathRecipient() {
+ if (mToken == null) {
+ return;
+ }
+
+ try {
+ mToken.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ // Client died, do nothing
+ }
+ }
+
+ void unlinkFromDeathRecipient() {
+ if (mToken == null) {
+ return;
+ }
+
+ mToken.unlinkToDeath(this, 0);
+ }
+
void layout(int dw, int dh) {
mWindowHandle.touchableRegion.set(0, 0, dw, dh);
mWindowHandle.frameLeft = 0;
@@ -86,5 +121,19 @@ class InputConsumerImpl {
mService.mInputManager.unregisterInputChannel(mServerChannel);
mClientChannel.dispose();
mServerChannel.dispose();
+ unlinkFromDeathRecipient();
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mService.getWindowManagerLock()) {
+ // Clean up the input consumer
+ mService.mInputMonitor.destroyInputConsumer(mName);
+ unlinkFromDeathRecipient();
+ }
+ }
+
+ void dump(PrintWriter pw, String name, String prefix) {
+ pw.println(prefix + " name=" + name + " pid=" + mClientPid + " user=" + mClientUser);
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index cf1f1713a611..40eab45a26d9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLP
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
@@ -34,8 +35,11 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.app.ActivityManager;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.IBinder;
import android.os.Looper;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -43,7 +47,6 @@ import android.view.InputChannel;
import android.view.InputEventReceiver;
import android.view.KeyEvent;
import android.view.WindowManager;
-
import android.view.WindowManagerPolicy;
import com.android.server.input.InputApplicationHandle;
@@ -106,8 +109,9 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor,
Looper looper, String name,
- InputEventReceiver.Factory inputEventReceiverFactory) {
- super(service, name, null);
+ InputEventReceiver.Factory inputEventReceiverFactory,
+ int clientPid, UserHandle clientUser) {
+ super(service, null /* token */, name, null /* inputChannel */, clientPid, clientUser);
mInputMonitor = monitor;
mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
mClientChannel, looper);
@@ -129,6 +133,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
private void addInputConsumer(String name, InputConsumerImpl consumer) {
mInputConsumers.put(name, consumer);
+ consumer.linkToDeathRecipient();
updateInputWindowsLw(true /* force */);
}
@@ -166,17 +171,20 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
}
final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService,
- this, looper, name, inputEventReceiverFactory);
+ this, looper, name, inputEventReceiverFactory, Process.myPid(),
+ UserHandle.SYSTEM);
addInputConsumer(name, consumer);
return consumer;
}
- void createInputConsumer(String name, InputChannel inputChannel) {
+ void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
+ UserHandle clientUser) {
if (mInputConsumers.containsKey(name)) {
throw new IllegalStateException("Existing input consumer found with name: " + name);
}
- final InputConsumerImpl consumer = new InputConsumerImpl(mService, name, inputChannel);
+ final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name,
+ inputChannel, clientPid, clientUser);
switch (name) {
case INPUT_CONSUMER_WALLPAPER:
consumer.mWindowHandle.hasWallpaper = true;
@@ -593,7 +601,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
if (!inputConsumerKeys.isEmpty()) {
pw.println(prefix + "InputConsumers:");
for (String key : inputConsumerKeys) {
- pw.println(prefix + " name=" + key);
+ mInputConsumers.get(key).dump(pw, key, prefix);
}
}
}
@@ -690,7 +698,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
- mService.mDragDropController.mDragState.sendDragStartedIfNeededLw(w);
+ mService.mDragDropController.mDragState.sendDragStartedIfNeededLocked(w);
}
addInputWindowHandle(
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 717c5774f9f3..ad7c300a03fa 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -313,7 +313,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.prepareDrag(
- mService, mSurfaceSession, callerPid, callerUid, window, flags, width, height,
+ mSurfaceSession, callerPid, callerUid, window, flags, width, height,
outSurface);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -324,7 +324,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public boolean performDrag(IWindow window, IBinder dragToken,
int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
ClipData data) {
- return mDragDropController.performDrag(mService, window, dragToken, touchSource,
+ return mDragDropController.performDrag(window, dragToken, touchSource,
touchX, touchY, thumbCenterX, thumbCenterY, data);
}
@@ -332,7 +332,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public void reportDropResult(IWindow window, boolean consumed) {
final long ident = Binder.clearCallingIdentity();
try {
- mDragDropController.reportDropResult(mService, window, consumed);
+ mDragDropController.reportDropResult(window, consumed);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -342,7 +342,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public void cancelDragAndDrop(IBinder dragToken) {
final long ident = Binder.clearCallingIdentity();
try {
- mDragDropController.cancelDragAndDrop(mService, dragToken);
+ mDragDropController.cancelDragAndDrop(dragToken);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 87de1514c053..a11b33317f64 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.RESIZE_MODE_USER;
import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -210,9 +210,9 @@ class TaskPositioner implements DimLayer.DimLayerUser {
if (mCurrentDimSide != CTRL_NONE) {
final int createMode = mCurrentDimSide == CTRL_LEFT
- ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
- : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
- mService.mActivityManager.moveTaskToDockedStack(
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+ mService.mActivityManager.setTaskWindowingModeSplitScreenPrimary(
mTask.mTaskId, createMode, true /*toTop*/, true /* animate */,
null /* initialBounds */);
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 791accf8f347..7cee66ba064a 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -450,8 +450,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
// might change after a rotation and the original values will be invalid.
mService.setDockedStackCreateStateLocked(
(newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
- ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
- : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
null);
mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
}
@@ -708,7 +708,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
dockedStack.getRawBounds(mTmpRect2);
}
final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
- == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
getStackDockedModeBounds(mTmpRect, bounds, mTmpRect2,
mDisplayContent.mDividerControllerLocked.getContentWidth(),
dockedOnTopOrLeft);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 70035c355768..391f36e6b058 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -20,7 +20,7 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
@@ -137,7 +137,6 @@ import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
-import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -210,7 +209,6 @@ import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -560,7 +558,7 @@ public class WindowManagerService extends IWindowManager.Stub
// The root of the device window hierarchy.
RootWindowContainer mRoot;
- int mDockedStackCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Rect mDockedStackCreateBounds;
private final SparseIntArray mTmpTaskIds = new SparseIntArray();
@@ -751,7 +749,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mAllowTheaterModeWakeFromLayout;
TaskPositioner mTaskPositioner;
- final DragDropController mDragDropController = new DragDropController();
+ final DragDropController mDragDropController;
// For frozen screen animations.
private int mExitAnimId, mEnterAnimId;
@@ -771,110 +769,6 @@ public class WindowManagerService extends IWindowManager.Stub
private WindowContentFrameStats mTempWindowRenderStats;
- final class DragInputEventReceiver extends InputEventReceiver {
- // Set, if stylus button was down at the start of the drag.
- private boolean mStylusButtonDownAtStart;
- // Indicates the first event to check for button state.
- private boolean mIsStartEvent = true;
- // Set to true to ignore input events after the drag gesture is complete but the drag events
- // are still being dispatched.
- private boolean mMuteInput = false;
-
- public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- }
-
- @Override
- public void onInputEvent(InputEvent event, int displayId) {
- boolean handled = false;
- try {
- if (mDragDropController.mDragState == null) {
- // The drag has ended but the clean-up message has not been processed by
- // window manager. Drop events that occur after this until window manager
- // has a chance to clean-up the input handle.
- handled = true;
- return;
- }
- if (event instanceof MotionEvent
- && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0
- && !mMuteInput) {
- final MotionEvent motionEvent = (MotionEvent)event;
- boolean endDrag = false;
- final float newX = motionEvent.getRawX();
- final float newY = motionEvent.getRawY();
- final boolean isStylusButtonDown =
- (motionEvent.getButtonState() & MotionEvent.BUTTON_STYLUS_PRIMARY) != 0;
-
- if (mIsStartEvent) {
- if (isStylusButtonDown) {
- // First event and the button was down, check for the button being
- // lifted in the future, if that happens we'll drop the item.
- mStylusButtonDownAtStart = true;
- }
- mIsStartEvent = false;
- }
-
- switch (motionEvent.getAction()) {
- case MotionEvent.ACTION_DOWN: {
- if (DEBUG_DRAG) {
- Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
- }
- } break;
-
- case MotionEvent.ACTION_MOVE: {
- if (mStylusButtonDownAtStart && !isStylusButtonDown) {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "Button no longer pressed; dropping at "
- + newX + "," + newY);
- mMuteInput = true;
- synchronized (mWindowMap) {
- endDrag = mDragDropController.mDragState.notifyDropLw(newX, newY);
- }
- } else {
- synchronized (mWindowMap) {
- // move the surface and tell the involved window(s) where we are
- mDragDropController.mDragState.notifyMoveLw(newX, newY);
- }
- }
- } break;
-
- case MotionEvent.ACTION_UP: {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "Got UP on move channel; dropping at "
- + newX + "," + newY);
- mMuteInput = true;
- synchronized (mWindowMap) {
- endDrag = mDragDropController.mDragState.notifyDropLw(newX, newY);
- }
- } break;
-
- case MotionEvent.ACTION_CANCEL: {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
- mMuteInput = true;
- endDrag = true;
- } break;
- }
-
- if (endDrag) {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag ended; tearing down state");
- // tell all the windows that the drag has ended
- synchronized (mWindowMap) {
- // endDragLw will post back to looper to dispose the receiver
- // since we still need the receiver for the last finishInputEvent.
- mDragDropController.mDragState.endDragLw();
- }
- mStylusButtonDownAtStart = false;
- mIsStartEvent = true;
- }
-
- handled = true;
- }
- } catch (Exception e) {
- Slog.e(TAG_WM, "Exception caught by drag handleMotion", e);
- } finally {
- finishInputEvent(event, handled);
- }
- }
- }
-
/**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
@@ -1164,6 +1058,7 @@ public class WindowManagerService extends IWindowManager.Stub
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
+ mDragDropController = new DragDropController(this, mH.getLooper());
LocalServices.addService(WindowManagerInternal.class, new LocalService());
initPolicy();
@@ -4796,8 +4691,6 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int APP_FREEZE_TIMEOUT = 17;
public static final int SEND_NEW_CONFIGURATION = 18;
public static final int REPORT_WINDOWS_CHANGE = 19;
- public static final int DRAG_START_TIMEOUT = 20;
- public static final int DRAG_END_TIMEOUT = 21;
public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
public static final int BOOT_TIMEOUT = 23;
@@ -4824,8 +4717,6 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int UPDATE_DOCKED_STACK_DIVIDER = 41;
- public static final int TEAR_DOWN_DRAG_AND_DROP_INPUT = 44;
-
public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
@@ -5053,13 +4944,6 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
- case DRAG_START_TIMEOUT:
- case DRAG_END_TIMEOUT:
- case TEAR_DOWN_DRAG_AND_DROP_INPUT: {
- mDragDropController.handleMessage(WindowManagerService.this, msg);
- break;
- }
-
case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
notifyHardKeyboardStatusChange();
break;
@@ -6253,9 +6137,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void createInputConsumer(String name, InputChannel inputChannel) {
+ public void createInputConsumer(IBinder token, String name, InputChannel inputChannel) {
synchronized (mWindowMap) {
- mInputMonitor.createInputConsumer(name, inputChannel);
+ mInputMonitor.createInputConsumer(token, name, inputChannel, Binder.getCallingPid(),
+ Binder.getCallingUserHandle());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index 7a3432b56eb0..f5ea60ff5929 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -382,8 +382,8 @@ public class RecentTasksTest extends ActivityTestsBase {
assertSecurityException(expectCallable,
() -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mService.moveTaskToDockedStack(0, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, true,
- true, new Rect()));
+ () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect()));
assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
assertSecurityException(expectCallable,